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