]> sourceware.org Git - systemtap.git/blob - elaborate.cxx
Handle scalar statistics.
[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 (unsigned i = 0; i < sess.functions.size(); ++i)
916 sess.functions[i]->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 (unsigned i = 0; i < sess.functions.size(); ++i)
950 {
951 functiondecl * fn = sess.functions[i];
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 (unsigned i = 0; i < sess.functions.size(); ++i)
962 {
963 if (sess.functions[i]->body)
964 sess.functions[i]->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.push_back (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 for (unsigned j = 0; j < session.functions.size(); j++)
1739 {
1740 functiondecl* fd = session.functions[j];
1741 if (fd->name == name &&
1742 fd->formal_args.size() == arity)
1743 return fd;
1744 }
1745
1746 // search library globals
1747 for (unsigned i=0; i<session.library_files.size(); i++)
1748 {
1749 stapfile* f = session.library_files[i];
1750 for (unsigned j=0; j<f->functions.size(); j++)
1751 if (f->functions[j]->name == name &&
1752 f->functions[j]->formal_args.size() == arity)
1753 {
1754 // put library into the queue if not already there
1755 if (0) // session.verbose_resolution
1756 cerr << " function " << name << " "
1757 << "is defined from " << f->name << endl;
1758
1759 if (find (session.files.begin(), session.files.end(), f)
1760 == session.files.end())
1761 session.files.push_back (f);
1762 // else .. print different message?
1763
1764 return f->functions[j];
1765 }
1766 }
1767
1768 return 0;
1769 }
1770
1771
1772
1773 // ------------------------------------------------------------------------
1774 // optimization
1775
1776
1777 // Do away with functiondecls that are never (transitively) called
1778 // from probes.
1779 void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
1780 {
1781 functioncall_traversing_visitor ftv;
1782 for (unsigned i=0; i<s.probes.size(); i++)
1783 {
1784 s.probes[i]->body->visit (& ftv);
1785 if (s.probes[i]->sole_location()->condition)
1786 s.probes[i]->sole_location()->condition->visit (& ftv);
1787 }
1788 for (unsigned i=0; i<s.functions.size(); /* see below */)
1789 {
1790 if (ftv.traversed.find(s.functions[i]) == ftv.traversed.end())
1791 {
1792 if (s.functions[i]->tok->location.file == s.user_file->name && // !tapset
1793 ! s.suppress_warnings)
1794 s.print_warning ("eliding unused function '" + s.functions[i]->name + "'", s.functions[i]->tok);
1795 else if (s.verbose>2)
1796 clog << "Eliding unused function " << s.functions[i]->name
1797 << endl;
1798 if (s.tapset_compile_coverage) {
1799 s.unused_functions.push_back (s.functions[i]);
1800 }
1801 s.functions.erase (s.functions.begin() + i);
1802 relaxed_p = false;
1803 // NB: don't increment i
1804 }
1805 else
1806 i++;
1807 }
1808 }
1809
1810
1811 // ------------------------------------------------------------------------
1812
1813 // Do away with local & global variables that are never
1814 // written nor read.
1815 void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations)
1816 {
1817 varuse_collecting_visitor vut;
1818
1819 for (unsigned i=0; i<s.probes.size(); i++)
1820 {
1821 s.probes[i]->body->visit (& vut);
1822
1823 if (s.probes[i]->sole_location()->condition)
1824 s.probes[i]->sole_location()->condition->visit (& vut);
1825 }
1826
1827 // NB: Since varuse_collecting_visitor also traverses down
1828 // actually called functions, we don't need to explicitly
1829 // iterate over them. Uncalled ones should have been pruned
1830 // in _opt1 above.
1831 //
1832 // for (unsigned i=0; i<s.functions.size(); i++)
1833 // s.functions[i]->body->visit (& vut);
1834
1835 // Now in vut.read/written, we have a mixture of all locals, globals
1836
1837 for (unsigned i=0; i<s.probes.size(); i++)
1838 for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
1839 {
1840 vardecl* l = s.probes[i]->locals[j];
1841
1842 if (vut.read.find (l) == vut.read.end() &&
1843 vut.written.find (l) == vut.written.end())
1844 {
1845 if (l->tok->location.file == s.user_file->name && // !tapset
1846 ! s.suppress_warnings)
1847 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
1848 else if (s.verbose>2)
1849 clog << "Eliding unused local variable "
1850 << l->name << " in " << s.probes[i]->name << endl;
1851 if (s.tapset_compile_coverage) {
1852 s.probes[i]->unused_locals.push_back
1853 (s.probes[i]->locals[j]);
1854 }
1855 s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
1856 relaxed_p = false;
1857 // don't increment j
1858 }
1859 else
1860 {
1861 if (vut.written.find (l) == vut.written.end())
1862 if (iterations == 0 && ! s.suppress_warnings)
1863 {
1864 stringstream o;
1865 vector<vardecl*>::iterator it;
1866 for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++)
1867 if (l->name != (*it)->name)
1868 o << " " << (*it)->name;
1869 for (it = s.globals.begin(); it != s.globals.end(); it++)
1870 if (l->name != (*it)->name)
1871 o << " " << (*it)->name;
1872
1873 s.print_warning ("read-only local variable '" + l->name + "' " +
1874 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
1875 }
1876 j++;
1877 }
1878 }
1879
1880 for (unsigned i=0; i<s.functions.size(); i++)
1881 for (unsigned j=0; j<s.functions[i]->locals.size(); /* see below */)
1882 {
1883 vardecl* l = s.functions[i]->locals[j];
1884 if (vut.read.find (l) == vut.read.end() &&
1885 vut.written.find (l) == vut.written.end())
1886 {
1887 if (l->tok->location.file == s.user_file->name && // !tapset
1888 ! s.suppress_warnings)
1889 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
1890 else if (s.verbose>2)
1891 clog << "Eliding unused local variable "
1892 << l->name << " in function " << s.functions[i]->name
1893 << endl;
1894 if (s.tapset_compile_coverage) {
1895 s.functions[i]->unused_locals.push_back
1896 (s.functions[i]->locals[j]);
1897 }
1898 s.functions[i]->locals.erase(s.functions[i]->locals.begin() + j);
1899 relaxed_p = false;
1900 // don't increment j
1901 }
1902 else
1903 {
1904 if (vut.written.find (l) == vut.written.end())
1905 if (iterations == 0 && ! s.suppress_warnings)
1906 {
1907 stringstream o;
1908 vector<vardecl*>::iterator it;
1909 for ( it = s.functions[i]->formal_args.begin() ;
1910 it != s.functions[i]->formal_args.end(); it++)
1911 if (l->name != (*it)->name)
1912 o << " " << (*it)->name;
1913 for (it = s.functions[i]->locals.begin(); it != s.functions[i]->locals.end(); it++)
1914 if (l->name != (*it)->name)
1915 o << " " << (*it)->name;
1916 for (it = s.globals.begin(); it != s.globals.end(); it++)
1917 if (l->name != (*it)->name)
1918 o << " " << (*it)->name;
1919
1920 s.print_warning ("read-only local variable '" + l->name + "' " +
1921 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
1922 }
1923
1924 j++;
1925 }
1926 }
1927 for (unsigned i=0; i<s.globals.size(); /* see below */)
1928 {
1929 vardecl* l = s.globals[i];
1930 if (vut.read.find (l) == vut.read.end() &&
1931 vut.written.find (l) == vut.written.end())
1932 {
1933 if (l->tok->location.file == s.user_file->name && // !tapset
1934 ! s.suppress_warnings)
1935 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
1936 else if (s.verbose>2)
1937 clog << "Eliding unused global variable "
1938 << l->name << endl;
1939 if (s.tapset_compile_coverage) {
1940 s.unused_globals.push_back(s.globals[i]);
1941 }
1942 s.globals.erase(s.globals.begin() + i);
1943 relaxed_p = false;
1944 // don't increment i
1945 }
1946 else
1947 {
1948 if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer
1949 if (iterations == 0 && ! s.suppress_warnings)
1950 {
1951 stringstream o;
1952 vector<vardecl*>::iterator it;
1953 for (it = s.globals.begin(); it != s.globals.end(); it++)
1954 if (l->name != (*it)->name)
1955 o << " " << (*it)->name;
1956
1957 s.print_warning ("read-only global variable '" + l->name + "' " +
1958 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
1959 }
1960
1961 i++;
1962 }
1963 }
1964 }
1965
1966
1967 // ------------------------------------------------------------------------
1968
1969 struct dead_assignment_remover: public traversing_visitor
1970 {
1971 systemtap_session& session;
1972 bool& relaxed_p;
1973 const varuse_collecting_visitor& vut;
1974 expression** current_expr;
1975
1976 dead_assignment_remover(systemtap_session& s, bool& r,
1977 const varuse_collecting_visitor& v):
1978 session(s), relaxed_p(r), vut(v), current_expr(0) {}
1979
1980 void visit_expr_statement (expr_statement* s);
1981 // XXX: other places where an assignment may be nested should be
1982 // handled too (e.g., loop/if conditionals, array indexes, function
1983 // parameters). Until then, they result in visit_assignment() being
1984 // called with null current_expr.
1985
1986 void visit_assignment (assignment* e);
1987 void visit_binary_expression (binary_expression* e);
1988 void visit_arrayindex (arrayindex* e);
1989 void visit_functioncall (functioncall* e);
1990 void visit_if_statement (if_statement* e);
1991 void visit_for_loop (for_loop* e);
1992 };
1993
1994
1995 void
1996 dead_assignment_remover::visit_expr_statement (expr_statement* s)
1997 {
1998 expression** last_expr = current_expr;
1999 current_expr = & s->value;
2000 s->value->visit (this);
2001 s->tok = s->value->tok; // in case it was replaced
2002 current_expr = last_expr;
2003 }
2004
2005
2006 void
2007 dead_assignment_remover::visit_assignment (assignment* e)
2008 {
2009 symbol* left = get_symbol_within_expression (e->left);
2010 vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target
2011 if (current_expr && // see XXX above: this case represents a missed
2012 // optimization opportunity
2013 *current_expr == e && // we're not nested any deeper than expected
2014 leftvar) // not unresolved $target; intended sideeffect cannot be elided
2015 {
2016 expression** last_expr = current_expr;
2017 e->left->visit (this);
2018 current_expr = &e->right;
2019 e->right->visit (this);
2020 current_expr = last_expr;
2021
2022 if (vut.read.find(leftvar) == vut.read.end()) // var never read?
2023 {
2024 // NB: Not so fast! The left side could be an array whose
2025 // index expressions may have side-effects. This would be
2026 // OK if we could replace the array assignment with a
2027 // statement-expression containing all the index expressions
2028 // and the rvalue... but we can't.
2029 // Another possibility is that we have an unread global variable
2030 // which are kept for probe end value display.
2031
2032 bool is_global = false;
2033 vector<vardecl*>::iterator it;
2034 for (it = session.globals.begin(); it != session.globals.end(); it++)
2035 if (leftvar->name == (*it)->name)
2036 {
2037 is_global = true;
2038 break;
2039 }
2040
2041 varuse_collecting_visitor vut;
2042 e->left->visit (& vut);
2043 if (vut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars
2044 {
2045 /* PR 1119: NB: This is not necessary here. A write-only
2046 variable will also be elided soon at the next _opt2 iteration.
2047 if (e->left->tok->location.file == session.user_file->name && // !tapset
2048 ! session.suppress_warnings)
2049 clog << "WARNING: eliding write-only " << *e->left->tok << endl;
2050 else
2051 */
2052 if (session.verbose>2)
2053 clog << "Eliding assignment to " << leftvar->name
2054 << " at " << *e->tok << endl;
2055
2056 *current_expr = e->right; // goodbye assignment*
2057 relaxed_p = false;
2058 }
2059 }
2060 }
2061 }
2062
2063 void
2064 dead_assignment_remover::visit_binary_expression (binary_expression* e)
2065 {
2066 expression** last_expr = current_expr;
2067 current_expr = &e->left;
2068 e->left->visit (this);
2069 current_expr = &e->right;
2070 e->right->visit (this);
2071 current_expr = last_expr;
2072 }
2073
2074 void
2075 dead_assignment_remover::visit_arrayindex (arrayindex *e)
2076 {
2077 symbol *array = NULL;
2078 hist_op *hist = NULL;
2079 classify_indexable(e->base, array, hist);
2080
2081 if (array)
2082 {
2083 expression** last_expr = current_expr;
2084 for (unsigned i=0; i < e->indexes.size(); i++)
2085 {
2086 current_expr = & e->indexes[i];
2087 e->indexes[i]->visit (this);
2088 }
2089 current_expr = last_expr;
2090 }
2091 }
2092
2093 void
2094 dead_assignment_remover::visit_functioncall (functioncall* e)
2095 {
2096 expression** last_expr = current_expr;
2097 for (unsigned i=0; i<e->args.size(); i++)
2098 {
2099 current_expr = & e->args[i];
2100 e->args[i]->visit (this);
2101 }
2102 current_expr = last_expr;
2103 }
2104
2105 void
2106 dead_assignment_remover::visit_if_statement (if_statement* s)
2107 {
2108 expression** last_expr = current_expr;
2109 current_expr = & s->condition;
2110 s->condition->visit (this);
2111 s->thenblock->visit (this);
2112 if (s->elseblock)
2113 s->elseblock->visit (this);
2114 current_expr = last_expr;
2115 }
2116
2117 void
2118 dead_assignment_remover::visit_for_loop (for_loop* s)
2119 {
2120 expression** last_expr = current_expr;
2121 if (s->init) s->init->visit (this);
2122 current_expr = & s->cond;
2123 s->cond->visit (this);
2124 if (s->incr) s->incr->visit (this);
2125 s->block->visit (this);
2126 current_expr = last_expr;
2127 }
2128
2129 // Let's remove assignments to variables that are never read. We
2130 // rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to
2131 // be optimized away as an unused variable, and expr a candidate to be
2132 // removed as a side-effect-free statement expression. Wahoo!
2133 void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
2134 {
2135 // Recompute the varuse data, which will probably match the opt2
2136 // copy of the computation, except for those totally unused
2137 // variables that opt2 removed.
2138 varuse_collecting_visitor vut;
2139 for (unsigned i=0; i<s.probes.size(); i++)
2140 s.probes[i]->body->visit (& vut); // includes reachable functions too
2141
2142 dead_assignment_remover dar (s, relaxed_p, vut);
2143 // This instance may be reused for multiple probe/function body trims.
2144
2145 for (unsigned i=0; i<s.probes.size(); i++)
2146 s.probes[i]->body->visit (& dar);
2147 for (unsigned i=0; i<s.functions.size(); i++)
2148 s.functions[i]->body->visit (& dar);
2149 // The rewrite operation is performed within the visitor.
2150
2151 // XXX: we could also zap write-only globals here
2152 }
2153
2154
2155 // ------------------------------------------------------------------------
2156
2157 struct dead_stmtexpr_remover: public traversing_visitor
2158 {
2159 systemtap_session& session;
2160 bool& relaxed_p;
2161 statement** current_stmt; // pointer to current stmt* being iterated
2162 set<vardecl*> focal_vars; // vars considered subject to side-effects
2163
2164 dead_stmtexpr_remover(systemtap_session& s, bool& r):
2165 session(s), relaxed_p(r), current_stmt(0) {}
2166
2167 void visit_block (block *s);
2168 void visit_null_statement (null_statement *s);
2169 void visit_if_statement (if_statement* s);
2170 void visit_foreach_loop (foreach_loop *s);
2171 void visit_for_loop (for_loop *s);
2172 // XXX: and other places where stmt_expr's might be nested
2173
2174 void visit_expr_statement (expr_statement *s);
2175 };
2176
2177
2178 void
2179 dead_stmtexpr_remover::visit_null_statement (null_statement *s)
2180 {
2181 // easy!
2182 if (session.verbose>2)
2183 clog << "Eliding side-effect-free null statement " << *s->tok << endl;
2184 *current_stmt = 0;
2185 }
2186
2187
2188 void
2189 dead_stmtexpr_remover::visit_block (block *s)
2190 {
2191 vector<statement*> new_stmts;
2192 for (unsigned i=0; i<s->statements.size(); i++ )
2193 {
2194 statement** last_stmt = current_stmt;
2195 current_stmt = & s->statements[i];
2196 s->statements[i]->visit (this);
2197 if (*current_stmt != 0)
2198 {
2199 // flatten nested blocks into this one
2200 block *b = dynamic_cast<block *>(*current_stmt);
2201 if (b)
2202 {
2203 if (session.verbose>2)
2204 clog << "Flattening nested block " << *b->tok << endl;
2205 new_stmts.insert(new_stmts.end(),
2206 b->statements.begin(), b->statements.end());
2207 relaxed_p = false;
2208 }
2209 else
2210 new_stmts.push_back (*current_stmt);
2211 }
2212 current_stmt = last_stmt;
2213 }
2214 if (new_stmts.size() == 0)
2215 {
2216 if (session.verbose>2)
2217 clog << "Eliding side-effect-free empty block " << *s->tok << endl;
2218 *current_stmt = 0;
2219 }
2220 else if (new_stmts.size() == 1)
2221 {
2222 if (session.verbose>2)
2223 clog << "Eliding side-effect-free singleton block " << *s->tok << endl;
2224 *current_stmt = new_stmts[0];
2225 }
2226 else
2227 {
2228 s->statements = new_stmts;
2229 }
2230 }
2231
2232 void
2233 dead_stmtexpr_remover::visit_if_statement (if_statement *s)
2234 {
2235 statement** last_stmt = current_stmt;
2236 current_stmt = & s->thenblock;
2237 s->thenblock->visit (this);
2238
2239 if (s->elseblock)
2240 {
2241 current_stmt = & s->elseblock;
2242 s->elseblock->visit (this);
2243 // null *current_stmt is OK here.
2244 }
2245 current_stmt = last_stmt;
2246
2247 if (s->thenblock == 0)
2248 {
2249 if (s->elseblock == 0)
2250 {
2251 // We may be able to elide this statement, if the condition
2252 // expression is side-effect-free.
2253 varuse_collecting_visitor vct;
2254 s->condition->visit(& vct);
2255 if (vct.side_effect_free ())
2256 {
2257 if (session.verbose>2)
2258 clog << "Eliding side-effect-free if statement "
2259 << *s->tok << endl;
2260 *current_stmt = 0; // yeah, baby
2261 }
2262 else
2263 {
2264 // We can still turn it into a simple expr_statement though...
2265 if (session.verbose>2)
2266 clog << "Creating simple evaluation from if statement "
2267 << *s->tok << endl;
2268 expr_statement *es = new expr_statement;
2269 es->value = s->condition;
2270 es->tok = es->value->tok;
2271 *current_stmt = es;
2272 }
2273 }
2274 else
2275 {
2276 // For an else without a then, we can invert the condition logic to
2277 // avoid having a null statement in the thenblock
2278 if (session.verbose>2)
2279 clog << "Inverting the condition of if statement "
2280 << *s->tok << endl;
2281 unary_expression *ue = new unary_expression;
2282 ue->operand = s->condition;
2283 ue->tok = ue->operand->tok;
2284 ue->op = "!";
2285 s->condition = ue;
2286 s->thenblock = s->elseblock;
2287 s->elseblock = 0;
2288 }
2289 }
2290 }
2291
2292 void
2293 dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
2294 {
2295 statement** last_stmt = current_stmt;
2296 current_stmt = & s->block;
2297 s->block->visit (this);
2298 current_stmt = last_stmt;
2299
2300 if (s->block == 0)
2301 {
2302 if (session.verbose>2)
2303 clog << "Eliding side-effect-free foreach statement " << *s->tok << endl;
2304 *current_stmt = 0; // yeah, baby
2305 }
2306 }
2307
2308 void
2309 dead_stmtexpr_remover::visit_for_loop (for_loop *s)
2310 {
2311 statement** last_stmt = current_stmt;
2312 current_stmt = & s->block;
2313 s->block->visit (this);
2314 current_stmt = last_stmt;
2315
2316 if (s->block == 0)
2317 {
2318 // We may be able to elide this statement, if the condition
2319 // expression is side-effect-free.
2320 varuse_collecting_visitor vct;
2321 if (s->init) s->init->visit(& vct);
2322 s->cond->visit(& vct);
2323 if (s->incr) s->incr->visit(& vct);
2324 if (vct.side_effect_free ())
2325 {
2326 if (session.verbose>2)
2327 clog << "Eliding side-effect-free for statement " << *s->tok << endl;
2328 *current_stmt = 0; // yeah, baby
2329 return;
2330 }
2331
2332 // Can't elide this whole statement; put a null in there.
2333 s->block = new null_statement();
2334 s->block->tok = s->tok;
2335 }
2336 }
2337
2338
2339
2340 void
2341 dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
2342 {
2343 // Run a varuse query against the operand expression. If it has no
2344 // side-effects, replace the entire statement expression by a null
2345 // statement. This replacement is done by overwriting the
2346 // current_stmt pointer.
2347 //
2348 // Unlike many other visitors, we do *not* traverse this outermost
2349 // one into the expression subtrees. There is no need - no
2350 // expr_statement nodes will be found there. (Function bodies
2351 // need to be visited explicitly by our caller.)
2352 //
2353 // NB. While we don't share nodes in the parse tree, let's not
2354 // deallocate *s anyway, just in case...
2355
2356 varuse_collecting_visitor vut;
2357 s->value->visit (& vut);
2358
2359 if (vut.side_effect_free_wrt (focal_vars) &&
2360 *current_stmt == s) // we're not nested any deeper than expected
2361 {
2362 /* PR 1119: NB: this message is not a good idea here. It can
2363 name some arbitrary RHS expression of an assignment.
2364 if (s->value->tok->location.file == session.user_file->name && // not tapset
2365 ! session.suppress_warnings)
2366 clog << "WARNING: eliding read-only " << *s->value->tok << endl;
2367 else
2368 */
2369 if (session.verbose>2)
2370 clog << "Eliding side-effect-free expression "
2371 << *s->tok << endl;
2372
2373 // NB: this 0 pointer is invalid to leave around for any length of
2374 // time, but the parent parse tree objects above handle it.
2375 * current_stmt = 0;
2376
2377 relaxed_p = false;
2378 }
2379 }
2380
2381
2382 void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
2383 {
2384 // Finally, let's remove some statement-expressions that have no
2385 // side-effect. These should be exactly those whose private varuse
2386 // visitors come back with an empty "written" and "embedded" lists.
2387
2388 dead_stmtexpr_remover duv (s, relaxed_p);
2389 // This instance may be reused for multiple probe/function body trims.
2390
2391 for (unsigned i=0; i<s.probes.size(); i++)
2392 {
2393 derived_probe* p = s.probes[i];
2394
2395 duv.focal_vars.clear ();
2396 duv.focal_vars.insert (s.globals.begin(),
2397 s.globals.end());
2398 duv.focal_vars.insert (p->locals.begin(),
2399 p->locals.end());
2400
2401 duv.current_stmt = & p->body;
2402 p->body->visit (& duv);
2403 if (p->body == 0)
2404 {
2405 if (! s.suppress_warnings)
2406 s.print_warning ("side-effect-free probe '" + p->name + "'", p->tok);
2407
2408 p->body = new null_statement();
2409 p->body->tok = p->tok;
2410
2411 // XXX: possible duplicate warnings; see below
2412 }
2413 }
2414 for (unsigned i=0; i<s.functions.size(); i++)
2415 {
2416 functiondecl* fn = s.functions[i];
2417 duv.focal_vars.clear ();
2418 duv.focal_vars.insert (fn->locals.begin(),
2419 fn->locals.end());
2420 duv.focal_vars.insert (fn->formal_args.begin(),
2421 fn->formal_args.end());
2422 duv.focal_vars.insert (s.globals.begin(),
2423 s.globals.end());
2424
2425 duv.current_stmt = & fn->body;
2426 fn->body->visit (& duv);
2427 if (fn->body == 0)
2428 {
2429 if (! s.suppress_warnings)
2430 s.print_warning ("side-effect-free function '" + fn->name + "'", fn->tok);
2431
2432 fn->body = new null_statement();
2433 fn->body->tok = fn->tok;
2434
2435 // XXX: the next iteration of the outer optimization loop may
2436 // take this new null_statement away again, and thus give us a
2437 // fresh warning. It would be better if this fixup was performed
2438 // only after the relaxation iterations.
2439 // XXX: or else see bug #6469.
2440 }
2441 }
2442 }
2443
2444
2445 // ------------------------------------------------------------------------
2446
2447 // The goal of this visitor is to reduce top-level expressions in void context
2448 // into separate statements that evaluate each subcomponent of the expression.
2449 // The dead-statement-remover can later remove some parts if they have no side
2450 // effects.
2451 struct void_statement_reducer: public traversing_visitor
2452 {
2453 systemtap_session& session;
2454 bool& relaxed_p;
2455 statement** current_stmt; // pointer to current stmt* being iterated
2456 expr_statement* current_expr; // pointer to current expr being iterated
2457 set<vardecl*> focal_vars; // vars considered subject to side-effects
2458
2459 void_statement_reducer(systemtap_session& s, bool& r):
2460 session(s), relaxed_p(r), current_stmt(0), current_expr(0) {}
2461
2462 // these just maintain current_stmt while recursing, but don't visit
2463 // expressions in the conditional / loop controls.
2464 void visit_expr_statement (expr_statement* s);
2465 void visit_block (block *s);
2466 void visit_if_statement (if_statement* s);
2467 void visit_for_loop (for_loop* s);
2468 void visit_foreach_loop (foreach_loop* s);
2469
2470 // these expressions get rewritten into their statement equivalents
2471 void visit_logical_or_expr (logical_or_expr* e);
2472 void visit_logical_and_expr (logical_and_expr* e);
2473 void visit_ternary_expression (ternary_expression* e);
2474
2475 // all of these can be reduced into simpler statements
2476 void visit_binary_expression (binary_expression* e);
2477 void visit_unary_expression (unary_expression* e);
2478 void visit_comparison (comparison* e);
2479 void visit_concatenation (concatenation* e);
2480 void visit_functioncall (functioncall* e);
2481 void visit_print_format (print_format* e);
2482
2483 // these are a bit hairy to grok due to the intricacies of indexables and
2484 // stats, so I'm chickening out and skipping them...
2485 void visit_array_in (array_in* e) {}
2486 void visit_arrayindex (arrayindex* e) {}
2487 void visit_stat_op (stat_op* e) {}
2488 void visit_hist_op (hist_op* e) {}
2489
2490 // these can't be reduced because they always have an effect
2491 void visit_return_statement (return_statement* s) {}
2492 void visit_delete_statement (delete_statement* s) {}
2493 void visit_pre_crement (pre_crement* e) {}
2494 void visit_post_crement (post_crement* e) {}
2495 void visit_assignment (assignment* e) {}
2496 };
2497
2498
2499 void
2500 void_statement_reducer::visit_expr_statement (expr_statement* s)
2501 {
2502 assert(!current_expr); // it shouldn't be possible to have nested expr's
2503 current_expr = s;
2504 s->value->visit (this);
2505 current_expr = NULL;
2506 }
2507
2508 void
2509 void_statement_reducer::visit_block (block *s)
2510 {
2511 statement** last_stmt = current_stmt;
2512 for (unsigned i=0; i<s->statements.size(); i++ )
2513 {
2514 current_stmt = & s->statements[i];
2515 s->statements[i]->visit (this);
2516 }
2517 current_stmt = last_stmt;
2518 }
2519
2520 void
2521 void_statement_reducer::visit_if_statement (if_statement* s)
2522 {
2523 statement** last_stmt = current_stmt;
2524 current_stmt = & s->thenblock;
2525 s->thenblock->visit (this);
2526
2527 if (s->elseblock)
2528 {
2529 current_stmt = & s->elseblock;
2530 s->elseblock->visit (this);
2531 }
2532 current_stmt = last_stmt;
2533 }
2534
2535 void
2536 void_statement_reducer::visit_for_loop (for_loop* s)
2537 {
2538 statement** last_stmt = current_stmt;
2539 current_stmt = & s->block;
2540 s->block->visit (this);
2541 current_stmt = last_stmt;
2542 }
2543
2544 void
2545 void_statement_reducer::visit_foreach_loop (foreach_loop* s)
2546 {
2547 statement** last_stmt = current_stmt;
2548 current_stmt = & s->block;
2549 s->block->visit (this);
2550 current_stmt = last_stmt;
2551 }
2552
2553 void
2554 void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
2555 {
2556 // In void context, the evaluation of "a || b" is exactly like
2557 // "if (!a) b", so let's do that instead.
2558
2559 assert(current_expr && current_expr->value == e);
2560
2561 if (session.verbose>2)
2562 clog << "Creating if statement from unused logical-or "
2563 << *e->tok << endl;
2564
2565 if_statement *is = new if_statement;
2566 is->tok = e->tok;
2567 is->elseblock = 0;
2568 *current_stmt = is;
2569 current_expr = NULL;
2570
2571 unary_expression *ue = new unary_expression;
2572 ue->operand = e->left;
2573 ue->tok = e->tok;
2574 ue->op = "!";
2575 is->condition = ue;
2576
2577 expr_statement *es = new expr_statement;
2578 es->value = e->right;
2579 es->tok = es->value->tok;
2580 is->thenblock = es;
2581
2582 is->visit(this);
2583 relaxed_p = false;
2584 }
2585
2586 void
2587 void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
2588 {
2589 // In void context, the evaluation of "a && b" is exactly like
2590 // "if (a) b", so let's do that instead.
2591
2592 assert(current_expr && current_expr->value == e);
2593
2594 if (session.verbose>2)
2595 clog << "Creating if statement from unused logical-and "
2596 << *e->tok << endl;
2597
2598 if_statement *is = new if_statement;
2599 is->tok = e->tok;
2600 is->elseblock = 0;
2601 is->condition = e->left;
2602 *current_stmt = is;
2603 current_expr = NULL;
2604
2605 expr_statement *es = new expr_statement;
2606 es->value = e->right;
2607 es->tok = es->value->tok;
2608 is->thenblock = es;
2609
2610 is->visit(this);
2611 relaxed_p = false;
2612 }
2613
2614 void
2615 void_statement_reducer::visit_ternary_expression (ternary_expression* e)
2616 {
2617 // In void context, the evaluation of "a ? b : c" is exactly like
2618 // "if (a) b else c", so let's do that instead.
2619
2620 assert(current_expr && current_expr->value == e);
2621
2622 if (session.verbose>2)
2623 clog << "Creating if statement from unused ternary expression "
2624 << *e->tok << endl;
2625
2626 if_statement *is = new if_statement;
2627 is->tok = e->tok;
2628 is->condition = e->cond;
2629 *current_stmt = is;
2630 current_expr = NULL;
2631
2632 expr_statement *es = new expr_statement;
2633 es->value = e->truevalue;
2634 es->tok = es->value->tok;
2635 is->thenblock = es;
2636
2637 es = new expr_statement;
2638 es->value = e->falsevalue;
2639 es->tok = es->value->tok;
2640 is->elseblock = es;
2641
2642 is->visit(this);
2643 relaxed_p = false;
2644 }
2645
2646 void
2647 void_statement_reducer::visit_binary_expression (binary_expression* e)
2648 {
2649 // When the result of a binary operation isn't needed, it's just as good to
2650 // evaluate the operands as sequential statements in a block.
2651
2652 assert(current_expr && current_expr->value == e);
2653
2654 if (session.verbose>2)
2655 clog << "Eliding unused binary " << *e->tok << endl;
2656
2657 block *b = new block;
2658 b->tok = current_expr->tok;
2659 *current_stmt = b;
2660 current_expr = NULL;
2661
2662 expr_statement *es = new expr_statement;
2663 es->value = e->left;
2664 es->tok = es->value->tok;
2665 b->statements.push_back(es);
2666
2667 es = new expr_statement;
2668 es->value = e->right;
2669 es->tok = es->value->tok;
2670 b->statements.push_back(es);
2671
2672 b->visit(this);
2673 relaxed_p = false;
2674 }
2675
2676 void
2677 void_statement_reducer::visit_unary_expression (unary_expression* e)
2678 {
2679 // When the result of a unary operation isn't needed, it's just as good to
2680 // evaluate the operand directly
2681
2682 assert(current_expr && current_expr->value == e);
2683
2684 if (session.verbose>2)
2685 clog << "Eliding unused unary " << *e->tok << endl;
2686
2687 current_expr->value = e->operand;
2688 current_expr->tok = current_expr->value->tok;
2689 current_expr->value->visit(this);
2690
2691 relaxed_p = false;
2692 }
2693
2694 void
2695 void_statement_reducer::visit_comparison (comparison* e)
2696 {
2697 visit_binary_expression(e);
2698 }
2699
2700 void
2701 void_statement_reducer::visit_concatenation (concatenation* e)
2702 {
2703 visit_binary_expression(e);
2704 }
2705
2706 void
2707 void_statement_reducer::visit_functioncall (functioncall* e)
2708 {
2709 // If a function call is pure and its result ignored, we can elide the call
2710 // and just evaluate the arguments in sequence
2711
2712 if (!e->args.size())
2713 return;
2714
2715 varuse_collecting_visitor vut;
2716 vut.traversed.insert (e->referent);
2717 vut.current_function = e->referent;
2718 e->referent->body->visit (& vut);
2719 if (!vut.side_effect_free_wrt (focal_vars))
2720 return;
2721
2722 assert(current_expr && current_expr->value == e);
2723
2724 if (session.verbose>2)
2725 clog << "Eliding side-effect-free function call " << *e->tok << endl;
2726
2727 block *b = new block;
2728 b->tok = e->tok;
2729 *current_stmt = b;
2730 current_expr = NULL;
2731
2732 for (unsigned i=0; i<e->args.size(); i++ )
2733 {
2734 expr_statement *es = new expr_statement;
2735 es->value = e->args[i];
2736 es->tok = es->value->tok;
2737 b->statements.push_back(es);
2738 }
2739
2740 b->visit(this);
2741 relaxed_p = false;
2742 }
2743
2744 void
2745 void_statement_reducer::visit_print_format (print_format* e)
2746 {
2747 // When an sprint's return value is ignored, we can simply evaluate the
2748 // arguments in sequence
2749
2750 if (e->print_to_stream || !e->args.size())
2751 return;
2752
2753 assert(current_expr && current_expr->value == e);
2754
2755 if (session.verbose>2)
2756 clog << "Eliding unused print " << *e->tok << endl;
2757
2758 block *b = new block;
2759 b->tok = e->tok;
2760 *current_stmt = b;
2761 current_expr = NULL;
2762
2763 for (unsigned i=0; i<e->args.size(); i++ )
2764 {
2765 expr_statement *es = new expr_statement;
2766 es->value = e->args[i];
2767 es->tok = es->value->tok;
2768 b->statements.push_back(es);
2769 }
2770
2771 b->visit(this);
2772 relaxed_p = false;
2773 }
2774
2775
2776 void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
2777 {
2778 // Let's simplify statements with unused computed values.
2779
2780 void_statement_reducer vuv (s, relaxed_p);
2781 // This instance may be reused for multiple probe/function body trims.
2782
2783 vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
2784
2785 for (unsigned i=0; i<s.probes.size(); i++)
2786 {
2787 derived_probe* p = s.probes[i];
2788 vuv.current_stmt = & p->body;
2789 p->body->visit (& vuv);
2790 }
2791 for (unsigned i=0; i<s.functions.size(); i++)
2792 {
2793 functiondecl* fn = s.functions[i];
2794 vuv.current_stmt = & fn->body;
2795 fn->body->visit (& vuv);
2796 }
2797 }
2798
2799
2800 struct duplicate_function_remover: public functioncall_traversing_visitor
2801 {
2802 systemtap_session& s;
2803 map<functiondecl*, functiondecl*>& duplicate_function_map;
2804
2805 duplicate_function_remover(systemtap_session& sess,
2806 map<functiondecl*, functiondecl*>&dfm):
2807 s(sess), duplicate_function_map(dfm) {};
2808
2809 void visit_functioncall (functioncall* e);
2810 };
2811
2812 void
2813 duplicate_function_remover::visit_functioncall (functioncall *e)
2814 {
2815 functioncall_traversing_visitor::visit_functioncall (e);
2816
2817 // If the current function call reference points to a function that
2818 // is a duplicate, replace it.
2819 if (duplicate_function_map.count(e->referent) != 0)
2820 {
2821 if (s.verbose>2)
2822 clog << "Changing " << e->referent->name
2823 << " reference to "
2824 << duplicate_function_map[e->referent]->name
2825 << " reference\n";
2826 e->tok = duplicate_function_map[e->referent]->tok;
2827 e->function = duplicate_function_map[e->referent]->name;
2828 e->referent = duplicate_function_map[e->referent];
2829 }
2830 }
2831
2832 static string
2833 get_functionsig (functiondecl* f)
2834 {
2835 ostringstream s;
2836
2837 // Get the "name:args body" of the function in s. We have to
2838 // include the args since the function 'x1(a, b)' is different than
2839 // the function 'x2(b, a)' even if the bodies of the two functions
2840 // are exactly the same.
2841 f->printsig(s);
2842 f->body->print(s);
2843
2844 // printsig puts f->name + ':' on the front. Remove this
2845 // (otherwise, functions would never compare equal).
2846 string str = s.str().erase(0, f->name.size() + 1);
2847
2848 // Return the function signature.
2849 return str;
2850 }
2851
2852 void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p)
2853 {
2854 // Walk through all the functions, looking for duplicates.
2855 map<string, functiondecl*> functionsig_map;
2856 map<functiondecl*, functiondecl*> duplicate_function_map;
2857 for (unsigned i=0; i < s.functions.size(); /* see below */)
2858 {
2859 string functionsig = get_functionsig(s.functions[i]);
2860
2861 if (functionsig_map.count(functionsig) == 0)
2862 {
2863 // This function is unique. Remember it.
2864 functionsig_map[functionsig] = s.functions[i];
2865 i++;
2866 }
2867 else
2868 {
2869 // This function is a duplicate.
2870 duplicate_function_map[s.functions[i]]
2871 = functionsig_map[functionsig];
2872
2873 // Remove the duplicate function (since we don't need it
2874 // anymore).
2875 s.functions.erase (s.functions.begin() + i);
2876
2877 relaxed_p = false;
2878 // NB: don't increment i
2879 }
2880 }
2881
2882 // If we have duplicate functions, traverse down the tree, replacing
2883 // the appropriate function calls.
2884 // duplicate_function_remover::visit_functioncall() handles the
2885 // details of replacing the function calls.
2886 if (duplicate_function_map.size() != 0)
2887 {
2888 duplicate_function_remover dfr (s, duplicate_function_map);
2889
2890 for (unsigned i=0; i < s.probes.size(); i++)
2891 s.probes[i]->body->visit(&dfr);
2892 }
2893 }
2894
2895
2896 static int
2897 semantic_pass_optimize1 (systemtap_session& s)
2898 {
2899 // In this pass, we attempt to rewrite probe/function bodies to
2900 // eliminate some blatantly unnecessary code. This is run before
2901 // type inference, but after symbol resolution and derived_probe
2902 // creation. We run an outer "relaxation" loop that repeats the
2903 // optimizations until none of them find anything to remove.
2904
2905 int rc = 0;
2906
2907 bool relaxed_p = false;
2908 unsigned iterations = 0;
2909 while (! relaxed_p)
2910 {
2911 if (pending_interrupts) break;
2912
2913 relaxed_p = true; // until proven otherwise
2914
2915 semantic_pass_opt1 (s, relaxed_p);
2916 semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0
2917 semantic_pass_opt3 (s, relaxed_p);
2918 semantic_pass_opt4 (s, relaxed_p);
2919 semantic_pass_opt5 (s, relaxed_p);
2920
2921 iterations ++;
2922 }
2923
2924 return rc;
2925 }
2926
2927
2928 static int
2929 semantic_pass_optimize2 (systemtap_session& s)
2930 {
2931 // This is run after type inference. We run an outer "relaxation"
2932 // loop that repeats the optimizations until none of them find
2933 // anything to remove.
2934
2935 int rc = 0;
2936
2937 bool relaxed_p = false;
2938 while (! relaxed_p)
2939 {
2940 if (pending_interrupts) break;
2941 relaxed_p = true; // until proven otherwise
2942
2943 semantic_pass_opt6 (s, relaxed_p);
2944 }
2945
2946 return rc;
2947 }
2948
2949
2950
2951 // ------------------------------------------------------------------------
2952 // type resolution
2953
2954
2955 static int
2956 semantic_pass_types (systemtap_session& s)
2957 {
2958 int rc = 0;
2959
2960 // next pass: type inference
2961 unsigned iterations = 0;
2962 typeresolution_info ti (s);
2963
2964 ti.assert_resolvability = false;
2965 // XXX: maybe convert to exception-based error signalling
2966 while (1)
2967 {
2968 if (pending_interrupts) break;
2969
2970 iterations ++;
2971 ti.num_newly_resolved = 0;
2972 ti.num_still_unresolved = 0;
2973
2974 for (unsigned j=0; j<s.functions.size(); j++)
2975 {
2976 if (pending_interrupts) break;
2977
2978 functiondecl* fn = s.functions[j];
2979 ti.current_probe = 0;
2980 ti.current_function = fn;
2981 ti.t = pe_unknown;
2982 fn->body->visit (& ti);
2983 // NB: we don't have to assert a known type for
2984 // functions here, to permit a "void" function.
2985 // The translator phase will omit the "retvalue".
2986 //
2987 // if (fn->type == pe_unknown)
2988 // ti.unresolved (fn->tok);
2989 }
2990
2991 for (unsigned j=0; j<s.probes.size(); j++)
2992 {
2993 if (pending_interrupts) break;
2994
2995 derived_probe* pn = s.probes[j];
2996 ti.current_function = 0;
2997 ti.current_probe = pn;
2998 ti.t = pe_unknown;
2999 pn->body->visit (& ti);
3000
3001 probe_point* pp = pn->sole_location();
3002 if (pp->condition)
3003 {
3004 ti.current_function = 0;
3005 ti.current_probe = 0;
3006 ti.t = pe_long; // NB: expected type
3007 pp->condition->visit (& ti);
3008 }
3009 }
3010
3011 for (unsigned j=0; j<s.globals.size(); j++)
3012 {
3013 vardecl* gd = s.globals[j];
3014 if (gd->type == pe_unknown)
3015 ti.unresolved (gd->tok);
3016 }
3017
3018 if (ti.num_newly_resolved == 0) // converged
3019 {
3020 if (ti.num_still_unresolved == 0)
3021 break; // successfully
3022 else if (! ti.assert_resolvability)
3023 ti.assert_resolvability = true; // last pass, with error msgs
3024 else
3025 { // unsuccessful conclusion
3026 rc ++;
3027 break;
3028 }
3029 }
3030 }
3031
3032 return rc + s.num_errors();
3033 }
3034
3035
3036
3037 typeresolution_info::typeresolution_info (systemtap_session& s):
3038 session(s), current_function(0), current_probe(0)
3039 {
3040 }
3041
3042
3043 void
3044 typeresolution_info::visit_literal_number (literal_number* e)
3045 {
3046 assert (e->type == pe_long);
3047 if ((t == e->type) || (t == pe_unknown))
3048 return;
3049
3050 mismatch (e->tok, e->type, t);
3051 }
3052
3053
3054 void
3055 typeresolution_info::visit_literal_string (literal_string* e)
3056 {
3057 assert (e->type == pe_string);
3058 if ((t == e->type) || (t == pe_unknown))
3059 return;
3060
3061 mismatch (e->tok, e->type, t);
3062 }
3063
3064
3065 void
3066 typeresolution_info::visit_logical_or_expr (logical_or_expr *e)
3067 {
3068 visit_binary_expression (e);
3069 }
3070
3071
3072 void
3073 typeresolution_info::visit_logical_and_expr (logical_and_expr *e)
3074 {
3075 visit_binary_expression (e);
3076 }
3077
3078
3079 void
3080 typeresolution_info::visit_comparison (comparison *e)
3081 {
3082 // NB: result of any comparison is an integer!
3083 if (t == pe_stats || t == pe_string)
3084 invalid (e->tok, t);
3085
3086 t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown;
3087 e->left->visit (this);
3088 t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown;
3089 e->right->visit (this);
3090
3091 if (e->left->type != pe_unknown &&
3092 e->right->type != pe_unknown &&
3093 e->left->type != e->right->type)
3094 mismatch (e->tok, e->left->type, e->right->type);
3095
3096 if (e->type == pe_unknown)
3097 {
3098 e->type = pe_long;
3099 resolved (e->tok, e->type);
3100 }
3101 }
3102
3103
3104 void
3105 typeresolution_info::visit_concatenation (concatenation *e)
3106 {
3107 if (t != pe_unknown && t != pe_string)
3108 invalid (e->tok, t);
3109
3110 t = pe_string;
3111 e->left->visit (this);
3112 t = pe_string;
3113 e->right->visit (this);
3114
3115 if (e->type == pe_unknown)
3116 {
3117 e->type = pe_string;
3118 resolved (e->tok, e->type);
3119 }
3120 }
3121
3122
3123 void
3124 typeresolution_info::visit_assignment (assignment *e)
3125 {
3126 if (t == pe_stats)
3127 invalid (e->tok, t);
3128
3129 if (e->op == "<<<") // stats aggregation
3130 {
3131 if (t == pe_string)
3132 invalid (e->tok, t);
3133
3134 t = pe_stats;
3135 e->left->visit (this);
3136 t = pe_long;
3137 e->right->visit (this);
3138 if (e->type == pe_unknown ||
3139 e->type == pe_stats)
3140 {
3141 e->type = pe_long;
3142 resolved (e->tok, e->type);
3143 }
3144 }
3145
3146 else if (e->left->type == pe_stats)
3147 invalid (e->left->tok, e->left->type);
3148
3149 else if (e->right->type == pe_stats)
3150 invalid (e->right->tok, e->right->type);
3151
3152 else if (e->op == "+=" || // numeric only
3153 e->op == "-=" ||
3154 e->op == "*=" ||
3155 e->op == "/=" ||
3156 e->op == "%=" ||
3157 e->op == "&=" ||
3158 e->op == "^=" ||
3159 e->op == "|=" ||
3160 e->op == "<<=" ||
3161 e->op == ">>=" ||
3162 false)
3163 {
3164 visit_binary_expression (e);
3165 }
3166 else if (e->op == ".=" || // string only
3167 false)
3168 {
3169 if (t == pe_long || t == pe_stats)
3170 invalid (e->tok, t);
3171
3172 t = pe_string;
3173 e->left->visit (this);
3174 t = pe_string;
3175 e->right->visit (this);
3176 if (e->type == pe_unknown)
3177 {
3178 e->type = pe_string;
3179 resolved (e->tok, e->type);
3180 }
3181 }
3182 else if (e->op == "=") // overloaded = for string & numeric operands
3183 {
3184 // logic similar to ternary_expression
3185 exp_type sub_type = t;
3186
3187 // Infer types across the l/r values
3188 if (sub_type == pe_unknown && e->type != pe_unknown)
3189 sub_type = e->type;
3190
3191 t = (sub_type != pe_unknown) ? sub_type :
3192 (e->right->type != pe_unknown) ? e->right->type :
3193 pe_unknown;
3194 e->left->visit (this);
3195 t = (sub_type != pe_unknown) ? sub_type :
3196 (e->left->type != pe_unknown) ? e->left->type :
3197 pe_unknown;
3198 e->right->visit (this);
3199
3200 if ((sub_type != pe_unknown) && (e->type == pe_unknown))
3201 {
3202 e->type = sub_type;
3203 resolved (e->tok, e->type);
3204 }
3205 if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
3206 {
3207 e->type = e->left->type;
3208 resolved (e->tok, e->type);
3209 }
3210
3211 if (e->left->type != pe_unknown &&
3212 e->right->type != pe_unknown &&
3213 e->left->type != e->right->type)
3214 mismatch (e->tok, e->left->type, e->right->type);
3215
3216 }
3217 else
3218 throw semantic_error ("unsupported assignment operator " + e->op);
3219 }
3220
3221
3222 void
3223 typeresolution_info::visit_binary_expression (binary_expression* e)
3224 {
3225 if (t == pe_stats || t == pe_string)
3226 invalid (e->tok, t);
3227
3228 t = pe_long;
3229 e->left->visit (this);
3230 t = pe_long;
3231 e->right->visit (this);
3232
3233 if (e->left->type != pe_unknown &&
3234 e->right->type != pe_unknown &&
3235 e->left->type != e->right->type)
3236 mismatch (e->tok, e->left->type, e->right->type);
3237
3238 if (e->type == pe_unknown)
3239 {
3240 e->type = pe_long;
3241 resolved (e->tok, e->type);
3242 }
3243 }
3244
3245
3246 void
3247 typeresolution_info::visit_pre_crement (pre_crement *e)
3248 {
3249 visit_unary_expression (e);
3250 }
3251
3252
3253 void
3254 typeresolution_info::visit_post_crement (post_crement *e)
3255 {
3256 visit_unary_expression (e);
3257 }
3258
3259
3260 void
3261 typeresolution_info::visit_unary_expression (unary_expression* e)
3262 {
3263 if (t == pe_stats || t == pe_string)
3264 invalid (e->tok, t);
3265
3266 t = pe_long;
3267 e->operand->visit (this);
3268
3269 if (e->type == pe_unknown)
3270 {
3271 e->type = pe_long;
3272 resolved (e->tok, e->type);
3273 }
3274 }
3275
3276
3277 void
3278 typeresolution_info::visit_ternary_expression (ternary_expression* e)
3279 {
3280 exp_type sub_type = t;
3281
3282 t = pe_long;
3283 e->cond->visit (this);
3284
3285 // Infer types across the true/false arms of the ternary expression.
3286
3287 if (sub_type == pe_unknown && e->type != pe_unknown)
3288 sub_type = e->type;
3289 t = sub_type;
3290 e->truevalue->visit (this);
3291 t = sub_type;
3292 e->falsevalue->visit (this);
3293
3294 if ((sub_type == pe_unknown) && (e->type != pe_unknown))
3295 ; // already resolved
3296 else if ((sub_type != pe_unknown) && (e->type == pe_unknown))
3297 {
3298 e->type = sub_type;
3299 resolved (e->tok, e->type);
3300 }
3301 else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown))
3302 {
3303 e->type = e->truevalue->type;
3304 resolved (e->tok, e->type);
3305 }
3306 else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown))
3307 {
3308 e->type = e->falsevalue->type;
3309 resolved (e->tok, e->type);
3310 }
3311 else if (e->type != sub_type)
3312 mismatch (e->tok, sub_type, e->type);
3313 }
3314
3315
3316 template <class Referrer, class Referent>
3317 void resolve_2types (Referrer* referrer, Referent* referent,
3318 typeresolution_info* r, exp_type t, bool accept_unknown = false)
3319 {
3320 exp_type& re_type = referrer->type;
3321 const token* re_tok = referrer->tok;
3322 exp_type& te_type = referent->type;
3323 const token* te_tok = referent->tok;
3324
3325 if (t != pe_unknown && re_type == t && re_type == te_type)
3326 ; // do nothing: all three e->types in agreement
3327 else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type)
3328 ; // do nothing: two known e->types in agreement
3329 else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type)
3330 r->mismatch (re_tok, re_type, te_type);
3331 else if (re_type != pe_unknown && t != pe_unknown && re_type != t)
3332 r->mismatch (re_tok, re_type, t);
3333 else if (te_type != pe_unknown && t != pe_unknown && te_type != t)
3334 r->mismatch (te_tok, te_type, t);
3335 else if (re_type == pe_unknown && t != pe_unknown)
3336 {
3337 // propagate from upstream
3338 re_type = t;
3339 r->resolved (re_tok, re_type);
3340 // catch re_type/te_type mismatch later
3341 }
3342 else if (re_type == pe_unknown && te_type != pe_unknown)
3343 {
3344 // propagate from referent
3345 re_type = te_type;
3346 r->resolved (re_tok, re_type);
3347 // catch re_type/t mismatch later
3348 }
3349 else if (re_type != pe_unknown && te_type == pe_unknown)
3350 {
3351 // propagate to referent
3352 te_type = re_type;
3353 r->resolved (te_tok, te_type);
3354 // catch re_type/t mismatch later
3355 }
3356 else if (! accept_unknown)
3357 r->unresolved (re_tok);
3358 }
3359
3360
3361 void
3362 typeresolution_info::visit_symbol (symbol* e)
3363 {
3364 assert (e->referent != 0);
3365 resolve_2types (e, e->referent, this, t);
3366 }
3367
3368
3369 void
3370 typeresolution_info::visit_target_symbol (target_symbol* e)
3371 {
3372 // This occurs only if a target symbol was not resolved over in
3373 // tapset.cxx land, that error was properly suppressed, and the
3374 // later unused-expression-elimination pass didn't get rid of it
3375 // either. So we have a target symbol that is believed to be of
3376 // genuine use, yet unresolved by the provider.
3377
3378 if (session.verbose > 2)
3379 {
3380 clog << "Resolution problem with ";
3381 if (current_function)
3382 {
3383 clog << "function " << current_function->name << endl;
3384 current_function->body->print (clog);
3385 clog << endl;
3386 }
3387 else if (current_probe)
3388 {
3389 clog << "probe " << current_probe->name << endl;
3390 current_probe->body->print (clog);
3391 clog << endl;
3392 }
3393 else
3394 clog << "other" << endl;
3395 }
3396
3397 if (e->saved_conversion_error)
3398 throw (* (e->saved_conversion_error));
3399 else
3400 throw semantic_error("unresolved target-symbol expression", e->tok);
3401 }
3402
3403
3404 void
3405 typeresolution_info::visit_arrayindex (arrayindex* e)
3406 {
3407
3408 symbol *array = NULL;
3409 hist_op *hist = NULL;
3410 classify_indexable(e->base, array, hist);
3411
3412 // Every hist_op has type [int]:int, that is to say, every hist_op
3413 // is a pseudo-one-dimensional integer array type indexed by
3414 // integers (bucket numbers).
3415
3416 if (hist)
3417 {
3418 if (e->indexes.size() != 1)
3419 unresolved (e->tok);
3420 t = pe_long;
3421 e->indexes[0]->visit (this);
3422 if (e->indexes[0]->type != pe_long)
3423 unresolved (e->tok);
3424 hist->visit (this);
3425 if (e->type != pe_long)
3426 {
3427 e->type = pe_long;
3428 resolved (e->tok, pe_long);
3429 }
3430 return;
3431 }
3432
3433 // Now we are left with "normal" map inference and index checking.
3434
3435 assert (array);
3436 assert (array->referent != 0);
3437 resolve_2types (e, array->referent, this, t);
3438
3439 // now resolve the array indexes
3440
3441 // if (e->referent->index_types.size() == 0)
3442 // // redesignate referent as array
3443 // e->referent->set_arity (e->indexes.size ());
3444
3445 if (e->indexes.size() != array->referent->index_types.size())
3446 unresolved (e->tok); // symbol resolution should prevent this
3447 else for (unsigned i=0; i<e->indexes.size(); i++)
3448 {
3449 expression* ee = e->indexes[i];
3450 exp_type& ft = array->referent->index_types [i];
3451 t = ft;
3452 ee->visit (this);
3453 exp_type at = ee->type;
3454
3455 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
3456 {
3457 // propagate to formal type
3458 ft = at;
3459 resolved (array->referent->tok, ft);
3460 // uses array decl as there is no token for "formal type"
3461 }
3462 if (at == pe_stats)
3463 invalid (ee->tok, at);
3464 if (ft == pe_stats)
3465 invalid (ee->tok, ft);
3466 if (at != pe_unknown && ft != pe_unknown && ft != at)
3467 mismatch (e->tok, at, ft);
3468 if (at == pe_unknown)
3469 unresolved (ee->tok);
3470 }
3471 }
3472
3473
3474 void
3475 typeresolution_info::visit_functioncall (functioncall* e)
3476 {
3477 assert (e->referent != 0);
3478
3479 resolve_2types (e, e->referent, this, t, true); // accept unknown type
3480
3481 if (e->type == pe_stats)
3482 invalid (e->tok, e->type);
3483
3484 // now resolve the function parameters
3485 if (e->args.size() != e->referent->formal_args.size())
3486 unresolved (e->tok); // symbol resolution should prevent this
3487 else for (unsigned i=0; i<e->args.size(); i++)
3488 {
3489 expression* ee = e->args[i];
3490 exp_type& ft = e->referent->formal_args[i]->type;
3491 const token* fe_tok = e->referent->formal_args[i]->tok;
3492 t = ft;
3493 ee->visit (this);
3494 exp_type at = ee->type;
3495
3496 if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown)
3497 {
3498 // propagate to formal arg
3499 ft = at;
3500 resolved (e->referent->formal_args[i]->tok, ft);
3501 }
3502 if (at == pe_stats)
3503 invalid (e->tok, at);
3504 if (ft == pe_stats)
3505 invalid (fe_tok, ft);
3506 if (at != pe_unknown && ft != pe_unknown && ft != at)
3507 mismatch (e->tok, at, ft);
3508 if (at == pe_unknown)
3509 unresolved (e->tok);
3510 }
3511 }
3512
3513
3514 void
3515 typeresolution_info::visit_block (block* e)
3516 {
3517 for (unsigned i=0; i<e->statements.size(); i++)
3518 {
3519 try
3520 {
3521 t = pe_unknown;
3522 e->statements[i]->visit (this);
3523 }
3524 catch (const semantic_error& e)
3525 {
3526 session.print_error (e);
3527 }
3528 }
3529 }
3530
3531
3532 void
3533 typeresolution_info::visit_embeddedcode (embeddedcode*)
3534 {
3535 }
3536
3537
3538 void
3539 typeresolution_info::visit_if_statement (if_statement* e)
3540 {
3541 t = pe_long;
3542 e->condition->visit (this);
3543
3544 t = pe_unknown;
3545 e->thenblock->visit (this);
3546
3547 if (e->elseblock)
3548 {
3549 t = pe_unknown;
3550 e->elseblock->visit (this);
3551 }
3552 }
3553
3554
3555 void
3556 typeresolution_info::visit_for_loop (for_loop* e)
3557 {
3558 t = pe_unknown;
3559 if (e->init) e->init->visit (this);
3560 t = pe_long;
3561 e->cond->visit (this);
3562 t = pe_unknown;
3563 if (e->incr) e->incr->visit (this);
3564 t = pe_unknown;
3565 e->block->visit (this);
3566 }
3567
3568
3569 void
3570 typeresolution_info::visit_foreach_loop (foreach_loop* e)
3571 {
3572 // See also visit_arrayindex.
3573 // This is different in that, being a statement, we can't assign
3574 // a type to the outer array, only propagate to/from the indexes
3575
3576 // if (e->referent->index_types.size() == 0)
3577 // // redesignate referent as array
3578 // e->referent->set_arity (e->indexes.size ());
3579
3580 symbol *array = NULL;
3581 hist_op *hist = NULL;
3582 classify_indexable(e->base, array, hist);
3583
3584 if (hist)
3585 {
3586 if (e->indexes.size() != 1)
3587 unresolved (e->tok);
3588 t = pe_long;
3589 e->indexes[0]->visit (this);
3590 if (e->indexes[0]->type != pe_long)
3591 unresolved (e->tok);
3592 hist->visit (this);
3593 }
3594 else
3595 {
3596 assert (array);
3597 if (e->indexes.size() != array->referent->index_types.size())
3598 unresolved (e->tok); // symbol resolution should prevent this
3599 else for (unsigned i=0; i<e->indexes.size(); i++)
3600 {
3601 expression* ee = e->indexes[i];
3602 exp_type& ft = array->referent->index_types [i];
3603 t = ft;
3604 ee->visit (this);
3605 exp_type at = ee->type;
3606
3607 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
3608 {
3609 // propagate to formal type
3610 ft = at;
3611 resolved (array->referent->tok, ft);
3612 // uses array decl as there is no token for "formal type"
3613 }
3614 if (at == pe_stats)
3615 invalid (ee->tok, at);
3616 if (ft == pe_stats)
3617 invalid (ee->tok, ft);
3618 if (at != pe_unknown && ft != pe_unknown && ft != at)
3619 mismatch (e->tok, at, ft);
3620 if (at == pe_unknown)
3621 unresolved (ee->tok);
3622 }
3623 }
3624
3625 if (e->limit)
3626 {
3627 t = pe_long;
3628 e->limit->visit (this);
3629 }
3630
3631 t = pe_unknown;
3632 e->block->visit (this);
3633 }
3634
3635
3636 void
3637 typeresolution_info::visit_null_statement (null_statement*)
3638 {
3639 }
3640
3641
3642 void
3643 typeresolution_info::visit_expr_statement (expr_statement* e)
3644 {
3645 t = pe_unknown;
3646 e->value->visit (this);
3647 }
3648
3649
3650 struct delete_statement_typeresolution_info:
3651 public throwing_visitor
3652 {
3653 typeresolution_info *parent;
3654 delete_statement_typeresolution_info (typeresolution_info *p):
3655 throwing_visitor ("invalid operand of delete expression"),
3656 parent (p)
3657 {}
3658
3659 void visit_arrayindex (arrayindex* e)
3660 {
3661 parent->visit_arrayindex (e);
3662 }
3663
3664 void visit_symbol (symbol* e)
3665 {
3666 exp_type ignored = pe_unknown;
3667 assert (e->referent != 0);
3668 resolve_2types (e, e->referent, parent, ignored);
3669 }
3670 };
3671
3672
3673 void
3674 typeresolution_info::visit_delete_statement (delete_statement* e)
3675 {
3676 delete_statement_typeresolution_info di (this);
3677 t = pe_unknown;
3678 e->value->visit (&di);
3679 }
3680
3681
3682 void
3683 typeresolution_info::visit_next_statement (next_statement*)
3684 {
3685 }
3686
3687
3688 void
3689 typeresolution_info::visit_break_statement (break_statement*)
3690 {
3691 }
3692
3693
3694 void
3695 typeresolution_info::visit_continue_statement (continue_statement*)
3696 {
3697 }
3698
3699
3700 void
3701 typeresolution_info::visit_array_in (array_in* e)
3702 {
3703 // all unary operators only work on numerics
3704 exp_type t1 = t;
3705 t = pe_unknown; // array value can be anything
3706 e->operand->visit (this);
3707
3708 if (t1 == pe_unknown && e->type != pe_unknown)
3709 ; // already resolved
3710 else if (t1 == pe_string || t1 == pe_stats)
3711 mismatch (e->tok, t1, pe_long);
3712 else if (e->type == pe_unknown)
3713 {
3714 e->type = pe_long;
3715 resolved (e->tok, e->type);
3716 }
3717 }
3718
3719
3720 void
3721 typeresolution_info::visit_return_statement (return_statement* e)
3722 {
3723 // This is like symbol, where the referent is
3724 // the return value of the function.
3725
3726 // translation pass will print error
3727 if (current_function == 0)
3728 return;
3729
3730 exp_type& e_type = current_function->type;
3731 t = current_function->type;
3732 e->value->visit (this);
3733
3734 if (e_type != pe_unknown && e->value->type != pe_unknown
3735 && e_type != e->value->type)
3736 mismatch (current_function->tok, e_type, e->value->type);
3737 if (e_type == pe_unknown &&
3738 (e->value->type == pe_long || e->value->type == pe_string))
3739 {
3740 // propagate non-statistics from value
3741 e_type = e->value->type;
3742 resolved (current_function->tok, e->value->type);
3743 }
3744 if (e->value->type == pe_stats)
3745 invalid (e->value->tok, e->value->type);
3746 }
3747
3748 void
3749 typeresolution_info::visit_print_format (print_format* e)
3750 {
3751 size_t unresolved_args = 0;
3752
3753 if (e->hist)
3754 {
3755 e->hist->visit(this);
3756 }
3757
3758 else if (e->print_with_format)
3759 {
3760 // If there's a format string, we can do both inference *and*
3761 // checking.
3762
3763 // First we extract the subsequence of formatting components
3764 // which are conversions (not just literal string components)
3765
3766 unsigned expected_num_args = 0;
3767 std::vector<print_format::format_component> components;
3768 for (size_t i = 0; i < e->components.size(); ++i)
3769 {
3770 if (e->components[i].type == print_format::conv_unspecified)
3771 throw semantic_error ("Unspecified conversion in print operator format string",
3772 e->tok);
3773 else if (e->components[i].type == print_format::conv_literal
3774 || e->components[i].type == print_format::conv_size)
3775 continue;
3776 components.push_back(e->components[i]);
3777 ++expected_num_args;
3778 if (e->components[i].widthtype == print_format::width_dynamic)
3779 ++expected_num_args;
3780 if (e->components[i].prectype == print_format::prec_dynamic)
3781 ++expected_num_args;
3782 }
3783
3784 // Then we check that the number of conversions and the number
3785 // of args agree.
3786
3787 if (expected_num_args != e->args.size())
3788 throw semantic_error ("Wrong number of args to formatted print operator",
3789 e->tok);
3790
3791 // Then we check that the types of the conversions match the types
3792 // of the args.
3793 unsigned argno = 0;
3794 for (size_t i = 0; i < components.size(); ++i)
3795 {
3796 // Check the dynamic width, if specified
3797 if (components[i].widthtype == print_format::width_dynamic)
3798 {
3799 check_arg_type (pe_long, e->args[argno]);
3800 ++argno;
3801 }
3802
3803 // Check the dynamic precision, if specified
3804 if (components[i].prectype == print_format::prec_dynamic)
3805 {
3806 check_arg_type (pe_long, e->args[argno]);
3807 ++argno;
3808 }
3809
3810 exp_type wanted = pe_unknown;
3811
3812 switch (components[i].type)
3813 {
3814 case print_format::conv_unspecified:
3815 case print_format::conv_literal:
3816 case print_format::conv_size:
3817 assert (false);
3818 break;
3819
3820 case print_format::conv_signed_decimal:
3821 case print_format::conv_unsigned_decimal:
3822 case print_format::conv_unsigned_octal:
3823 case print_format::conv_unsigned_ptr:
3824 case print_format::conv_unsigned_uppercase_hex:
3825 case print_format::conv_unsigned_lowercase_hex:
3826 case print_format::conv_binary:
3827 case print_format::conv_memory:
3828 wanted = pe_long;
3829 break;
3830
3831 case print_format::conv_string:
3832 wanted = pe_string;
3833 break;
3834 }
3835
3836 assert (wanted != pe_unknown);
3837 check_arg_type (wanted, e->args[argno]);
3838 ++argno;
3839 }
3840 }
3841 else
3842 {
3843 // Without a format string, the best we can do is require that
3844 // each argument resolve to a concrete type.
3845 for (size_t i = 0; i < e->args.size(); ++i)
3846 {
3847 t = pe_unknown;
3848 e->args[i]->visit (this);
3849 if (e->args[i]->type == pe_unknown)
3850 {
3851 unresolved (e->args[i]->tok);
3852 ++unresolved_args;
3853 }
3854 }
3855 }
3856
3857 if (unresolved_args == 0)
3858 {
3859 if (e->type == pe_unknown)
3860 {
3861 if (e->print_to_stream)
3862 e->type = pe_long;
3863 else
3864 e->type = pe_string;
3865 resolved (e->tok, e->type);
3866 }
3867 }
3868 else
3869 {
3870 e->type = pe_unknown;
3871 unresolved (e->tok);
3872 }
3873 }
3874
3875
3876 void
3877 typeresolution_info::visit_stat_op (stat_op* e)
3878 {
3879 t = pe_stats;
3880 e->stat->visit (this);
3881 if (e->type == pe_unknown)
3882 {
3883 e->type = pe_long;
3884 resolved (e->tok, e->type);
3885 }
3886 else if (e->type != pe_long)
3887 mismatch (e->tok, e->type, pe_long);
3888 }
3889
3890 void
3891 typeresolution_info::visit_hist_op (hist_op* e)
3892 {
3893 t = pe_stats;
3894 e->stat->visit (this);
3895 }
3896
3897
3898 void
3899 typeresolution_info::check_arg_type (exp_type wanted, expression* arg)
3900 {
3901 t = wanted;
3902 arg->visit (this);
3903
3904 if (arg->type == pe_unknown)
3905 {
3906 arg->type = wanted;
3907 resolved (arg->tok, wanted);
3908 }
3909 else if (arg->type != wanted)
3910 {
3911 mismatch (arg->tok, arg->type, wanted);
3912 }
3913 }
3914
3915
3916 void
3917 typeresolution_info::unresolved (const token* tok)
3918 {
3919 num_still_unresolved ++;
3920
3921 if (assert_resolvability)
3922 {
3923 stringstream msg;
3924 string nm = (current_function ? current_function->name :
3925 current_probe ? current_probe->name :
3926 "probe condition");
3927 msg << nm + " with unresolved type";
3928 session.print_error (semantic_error (msg.str(), tok));
3929 }
3930 }
3931
3932
3933 void
3934 typeresolution_info::invalid (const token* tok, exp_type pe)
3935 {
3936 num_still_unresolved ++;
3937
3938 if (assert_resolvability)
3939 {
3940 stringstream msg;
3941 string nm = (current_function ? current_function->name :
3942 current_probe ? current_probe->name :
3943 "probe condition");
3944 if (tok && tok->type == tok_operator)
3945 msg << nm + " uses invalid operator";
3946 else
3947 msg << nm + " with invalid type " << pe;
3948 session.print_error (semantic_error (msg.str(), tok));
3949 }
3950 }
3951
3952
3953 void
3954 typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
3955 {
3956 num_still_unresolved ++;
3957
3958 if (assert_resolvability)
3959 {
3960 stringstream msg;
3961 string nm = (current_function ? current_function->name :
3962 current_probe ? current_probe->name :
3963 "probe condition");
3964 msg << nm + " with type mismatch (" << t1 << " vs. " << t2 << ")";
3965 session.print_error (semantic_error (msg.str(), tok));
3966 }
3967 }
3968
3969
3970 void
3971 typeresolution_info::resolved (const token*, exp_type)
3972 {
3973 num_newly_resolved ++;
3974 }
3975
This page took 0.220401 seconds and 6 git commands to generate.