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