]> sourceware.org Git - systemtap.git/blame - elaborate.cxx
copyright year bump for translator
[systemtap.git] / elaborate.cxx
CommitLineData
2b066ec1 1// elaboration functions
1e6e9ec1 2// Copyright (C) 2005-2011 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"
2865d17a 12#include "translate.h"
2b066ec1 13#include "parse.h"
20c6c071 14#include "tapsets.h"
dc38c0ae 15#include "session.h"
72dbc915 16#include "util.h"
a057c85c 17#include "task_finder.h"
2b066ec1
FCE
18
19extern "C" {
20#include <sys/utsname.h>
a477f3f1 21#include <fnmatch.h>
4af765b2
LB
22#define __STDC_FORMAT_MACROS
23#include <inttypes.h>
2b066ec1
FCE
24}
25
2b066ec1 26#include <algorithm>
67c0a579
GH
27#include <fstream>
28#include <map>
29e64872 29#include <cassert>
67c0a579
GH
30#include <set>
31#include <vector>
1b07c728
FCE
32#include <algorithm>
33#include <iterator>
f4869658 34#include <climits>
1b07c728 35
2b066ec1 36
2b066ec1
FCE
37using namespace std;
38
39
40// ------------------------------------------------------------------------
41
5d23847d
FCE
42// Used in probe_point condition construction. Either argument may be
43// NULL; if both, return NULL too. Resulting expression is a deep
44// copy for symbol resolution purposes.
45expression* add_condition (expression* a, expression* b)
46{
47 if (!a && !b) return 0;
48 if (! a) return deep_copy_visitor::deep_copy(b);
49 if (! b) return deep_copy_visitor::deep_copy(a);
50 logical_and_expr la;
51 la.op = "&&";
52 la.left = a;
53 la.right = b;
54 la.tok = a->tok; // or could be b->tok
55 return deep_copy_visitor::deep_copy(& la);
56}
57
58// ------------------------------------------------------------------------
59
60
2b066ec1 61
4c5d1300 62derived_probe::derived_probe (probe *p, probe_point *l, bool rewrite_loc):
26e63673 63 base (p), base_pp(l), sdt_semaphore_addr(0), session_index((unsigned)-1)
2b066ec1 64{
5d23847d
FCE
65 assert (p);
66 this->tok = p->tok;
67 this->privileged = p->privileged;
68 this->body = deep_copy_visitor::deep_copy(p->body);
cbbe8080 69
5d23847d 70 assert (l);
4c5d1300
JS
71 // make a copy for subclasses which want to rewrite the location
72 if (rewrite_loc)
73 l = new probe_point(*l);
5d23847d 74 this->locations.push_back (l);
2b066ec1
FCE
75}
76
98afd80e 77
b8da0ad1
FCE
78void
79derived_probe::printsig (ostream& o) const
80{
81 probe::printsig (o);
82 printsig_nested (o);
83}
84
85void
86derived_probe::printsig_nested (ostream& o) const
87{
88 // We'd like to enclose the probe derivation chain in a /* */
89 // comment delimiter. But just printing /* base->printsig() */ is
90 // not enough, since base might itself be a derived_probe. So we,
91 // er, "cleverly" encode our nesting state as a formatting flag for
92 // the ostream.
93 ios::fmtflags f = o.flags (ios::internal);
94 if (f & ios::internal)
95 {
96 // already nested
97 o << " <- ";
98 base->printsig (o);
99 }
100 else
101 {
102 // outermost nesting
103 o << " /* <- ";
104 base->printsig (o);
105 o << " */";
106 }
107 // restore flags
108 (void) o.flags (f);
109}
110
111
c3a3c0c9 112void
2c5a19c6 113derived_probe::collect_derivation_chain (std::vector<probe*> &probes_list)
c3a3c0c9
WC
114{
115 probes_list.push_back(this);
116 base->collect_derivation_chain(probes_list);
117}
118
119
f1b9a51a
JS
120void
121derived_probe::collect_derivation_pp_chain (std::vector<probe_point*> &pp_list)
122{
123 pp_list.push_back(base_pp);
124 base->collect_derivation_pp_chain(pp_list);
125}
126
127
26e63673
JS
128string
129derived_probe::derived_locations ()
130{
131 ostringstream o;
132 vector<probe_point*> reference_point;
133 collect_derivation_pp_chain(reference_point);
134 for(unsigned i=0; i<reference_point.size(); ++i)
135 o << " from: " << reference_point[i]->str(false); // no ?,!,etc
136 return o.str();
137}
138
139
b20febf3 140probe_point*
b8da0ad1 141derived_probe::sole_location () const
dc38c0ae 142{
4af765b2
LB
143 if (locations.size() == 0 || locations.size() > 1)
144 throw semantic_error (ngettext("derived_probe with no locations",
145 "derived_probe with no locations",
146 locations.size()), this->tok);
57148ee7 147 else
b20febf3 148 return locations[0];
dc38c0ae
DS
149}
150
151
c3df9bce
JS
152probe_point*
153derived_probe::script_location () const
154{
155 const probe* p = almost_basest();
156 const probe_alias *a = p->get_alias();
157 const vector<probe_point*>& locs = a ? a->alias_names : p->locations;
4af765b2
LB
158 if (locs.size() == 0 || locs.size() > 1)
159 throw semantic_error (ngettext("derived_probe with no locations",
160 "derived_probe with too many locations",
161 locs.size()), this->tok);
c3df9bce
JS
162 else
163 return locs[0];
164}
165
166
2865d17a
DB
167void
168derived_probe::emit_unprivileged_assertion (translator_output* o)
169{
170 // Emit code which will cause compilation to fail if it is compiled in
171 // unprivileged mode.
172 o->newline() << "#ifndef STP_PRIVILEGED";
173 o->newline() << "#error Internal Error: Probe ";
174 probe::printsig (o->line());
175 o->line() << " generated in --unprivileged mode";
176 o->newline() << "#endif";
177}
178
179
180void
181derived_probe::emit_process_owner_assertion (translator_output* o)
182{
183 // Emit code which will abort should the current target not belong to the
184 // user in unprivileged mode.
185 o->newline() << "#ifndef STP_PRIVILEGED";
186 o->newline(1) << "if (! is_myproc ()) {";
187 o->newline(1) << "snprintf(c->error_buffer, sizeof(c->error_buffer),";
188 o->newline() << " \"Internal Error: Process %d does not belong to user %d in probe %s in --unprivileged mode\",";
189 o->newline() << " current->tgid, _stp_uid, c->probe_point);";
190 o->newline() << "c->last_error = c->error_buffer;";
991bd3ba
JS
191 // NB: since this check occurs before probe locking, its exit should
192 // not be a "goto out", which would attempt unlocking.
193 o->newline() << "return;";
2865d17a
DB
194 o->newline(-1) << "}";
195 o->newline(-1) << "#endif";
196}
197
8f6d8c2b
DB
198void
199derived_probe::print_dupe_stamp_unprivileged(ostream& o)
200{
4af765b2 201 o << _("unprivileged users: authorized") << endl;
8f6d8c2b
DB
202}
203
204void
205derived_probe::print_dupe_stamp_unprivileged_process_owner(ostream& o)
206{
4af765b2 207 o << _("unprivileged users: authorized for process owner") << endl;
8f6d8c2b 208}
47dd066d 209
20c6c071 210// ------------------------------------------------------------------------
98afd80e
FCE
211// Members of derived_probe_builder
212
213bool
214derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
215 const std::string& key,
216 std::string& value)
217{
218 map<string, literal *>::const_iterator i = params.find (key);
219 if (i == params.end())
220 return false;
221 literal_string * ls = dynamic_cast<literal_string *>(i->second);
222 if (!ls)
223 return false;
224 value = ls->value;
225 return true;
226}
227
20c6c071 228
98afd80e
FCE
229bool
230derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
231 const std::string& key,
232 int64_t& value)
233{
234 map<string, literal *>::const_iterator i = params.find (key);
235 if (i == params.end())
236 return false;
237 if (i->second == NULL)
238 return false;
239 literal_number * ln = dynamic_cast<literal_number *>(i->second);
240 if (!ln)
241 return false;
242 value = ln->value;
243 return true;
244}
245
246
888af770
FCE
247bool
248derived_probe_builder::has_null_param (std::map<std::string, literal*> const & params,
249 const std::string& key)
250{
251 map<string, literal *>::const_iterator i = params.find(key);
252 return (i != params.end() && i->second == NULL);
253}
254
255
98afd80e
FCE
256
257// ------------------------------------------------------------------------
20c6c071
GH
258// Members of match_key.
259
57148ee7
FCE
260match_key::match_key(string const & n)
261 : name(n),
262 have_parameter(false),
5d23847d 263 parameter_type(pe_unknown)
20c6c071
GH
264{
265}
266
267match_key::match_key(probe_point::component const & c)
268 : name(c.functor),
269 have_parameter(c.arg != NULL),
5d23847d 270 parameter_type(c.arg ? c.arg->type : pe_unknown)
20c6c071
GH
271{
272}
273
274match_key &
57148ee7 275match_key::with_number()
20c6c071
GH
276{
277 have_parameter = true;
5d23847d 278 parameter_type = pe_long;
20c6c071
GH
279 return *this;
280}
281
282match_key &
57148ee7 283match_key::with_string()
20c6c071
GH
284{
285 have_parameter = true;
5d23847d 286 parameter_type = pe_string;
20c6c071
GH
287 return *this;
288}
289
57148ee7 290string
20c6c071
GH
291match_key::str() const
292{
293 if (have_parameter)
294 switch (parameter_type)
295 {
5d23847d
FCE
296 case pe_string: return name + "(string)";
297 case pe_long: return name + "(number)";
20c6c071
GH
298 default: return name + "(...)";
299 }
300 return name;
301}
302
57148ee7 303bool
20c6c071
GH
304match_key::operator<(match_key const & other) const
305{
306 return ((name < other.name)
57148ee7
FCE
307
308 || (name == other.name
20c6c071 309 && have_parameter < other.have_parameter)
57148ee7
FCE
310
311 || (name == other.name
312 && have_parameter == other.have_parameter
20c6c071
GH
313 && parameter_type < other.parameter_type));
314}
2b066ec1 315
c0c7b466
FCE
316
317// NB: these are only used in the probe point name components, where
318// only "*" is permitted.
319//
320// Within module("bar"), function("foo"), process("baz") strings, real
321// wildcards are permitted too. See also util.h:contains_glob_chars
322
a477f3f1
DS
323static bool
324isglob(string const & str)
325{
326 return(str.find('*') != str.npos);
327}
328
122b4fcd
JS
329static bool
330isdoubleglob(string const & str)
331{
332 return(str.find("**") != str.npos);
333}
334
a477f3f1
DS
335bool
336match_key::globmatch(match_key const & other) const
337{
338 const char *other_str = other.name.c_str();
339 const char *name_str = name.c_str();
340
341 return ((fnmatch(name_str, other_str, FNM_NOESCAPE) == 0)
57148ee7 342 && have_parameter == other.have_parameter
a477f3f1
DS
343 && parameter_type == other.parameter_type);
344}
345
2b066ec1 346// ------------------------------------------------------------------------
20c6c071
GH
347// Members of match_node
348// ------------------------------------------------------------------------
349
27dc09b1
DB
350match_node::match_node() :
351 unprivileged_ok(false)
d4935c2f 352{
d4935c2f 353}
20c6c071
GH
354
355match_node *
57148ee7 356match_node::bind(match_key const & k)
20c6c071 357{
b4ceace2 358 if (k.name == "*")
4af765b2 359 throw semantic_error(_("invalid use of wildcard probe point component"));
b4ceace2 360
20c6c071
GH
361 map<match_key, match_node *>::const_iterator i = sub.find(k);
362 if (i != sub.end())
363 return i->second;
364 match_node * n = new match_node();
365 sub.insert(make_pair(k, n));
366 return n;
367}
368
57148ee7 369void
20c6c071
GH
370match_node::bind(derived_probe_builder * e)
371{
2531fc1e 372 ends.push_back (e);
20c6c071
GH
373}
374
57148ee7 375match_node *
20c6c071
GH
376match_node::bind(string const & k)
377{
378 return bind(match_key(k));
379}
380
381match_node *
382match_node::bind_str(string const & k)
383{
384 return bind(match_key(k).with_string());
385}
386
57148ee7 387match_node *
20c6c071
GH
388match_node::bind_num(string const & k)
389{
390 return bind(match_key(k).with_number());
391}
392
27dc09b1
DB
393match_node *
394match_node::bind_unprivileged(bool b)
395{
396 unprivileged_ok = b;
397 return this;
398}
399
b4ceace2
FCE
400void
401match_node::find_and_build (systemtap_session& s,
402 probe* p, probe_point *loc, unsigned pos,
403 vector<derived_probe *>& results)
20c6c071 404{
b4ceace2 405 assert (pos <= loc->components.size());
57148ee7 406 if (pos == loc->components.size()) // matched all probe point components so far
20c6c071 407 {
2531fc1e 408 if (ends.empty())
b4ceace2
FCE
409 {
410 string alternatives;
411 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
412 alternatives += string(" ") + i->first.str();
413
4af765b2
LB
414 throw semantic_error (_F("probe point truncated at position %s (follow: %s)",
415 lex_cast(pos).c_str(), alternatives.c_str()),
416 loc->components.back()->tok);
b4ceace2
FCE
417 }
418
27dc09b1
DB
419 if (s.unprivileged && ! unprivileged_ok)
420 {
4af765b2
LB
421 throw semantic_error (_("probe point is not allowed for unprivileged users"),
422 loc->components.back()->tok);
27dc09b1
DB
423 }
424
b4ceace2
FCE
425 map<string, literal *> param_map;
426 for (unsigned i=0; i<pos; i++)
427 param_map[loc->components[i]->functor] = loc->components[i]->arg;
428 // maybe 0
429
2531fc1e
FCE
430 // Iterate over all bound builders
431 for (unsigned k=0; k<ends.size(); k++)
432 {
433 derived_probe_builder *b = ends[k];
434 b->build (s, p, loc, param_map, results);
435 }
20c6c071 436 }
122b4fcd
JS
437 else if (isdoubleglob(loc->components[pos]->functor)) // ** wildcard?
438 {
439 unsigned int num_results = results.size();
440
441 // When faced with "foo**bar", we try "foo*bar" and "foo*.**bar"
442
443 const probe_point::component *comp = loc->components[pos];
444 const string &functor = comp->functor;
445 size_t glob_start = functor.find("**");
446 size_t glob_end = functor.find_first_not_of('*', glob_start);
447 const string prefix = functor.substr(0, glob_start);
448 const string suffix = ((glob_end != string::npos) ?
449 functor.substr(glob_end) : "");
450
451 // Synthesize "foo*bar"
452 probe_point *simple_pp = new probe_point(*loc);
453 probe_point::component *simple_comp = new probe_point::component(*comp);
454 simple_comp->functor = prefix + "*" + suffix;
455 simple_pp->components[pos] = simple_comp;
456 try
457 {
458 find_and_build (s, p, simple_pp, pos, results);
459 }
460 catch (const semantic_error& e)
461 {
462 // Ignore semantic_errors, but cleanup
463 delete simple_pp;
464 delete simple_comp;
465 }
466
467 // Synthesize "foo*.**bar"
468 // NB: any component arg should attach to the latter part only
469 probe_point *expanded_pp = new probe_point(*loc);
470 probe_point::component *expanded_comp_pre = new probe_point::component(*comp);
471 expanded_comp_pre->functor = prefix + "*";
472 expanded_comp_pre->arg = NULL;
473 probe_point::component *expanded_comp_post = new probe_point::component(*comp);
474 expanded_comp_post->functor = "**" + suffix;
475 expanded_pp->components[pos] = expanded_comp_pre;
476 expanded_pp->components.insert(expanded_pp->components.begin() + pos + 1,
477 expanded_comp_post);
478 try
479 {
480 find_and_build (s, p, expanded_pp, pos, results);
481 }
482 catch (const semantic_error& e)
483 {
484 // Ignore semantic_errors, but cleanup
485 delete expanded_pp;
486 delete expanded_comp_pre;
487 delete expanded_comp_post;
488 }
489
490 if (! loc->optional && num_results == results.size())
491 {
492 // We didn't find any wildcard matches (since the size of
493 // the result vector didn't change). Throw an error.
494 string alternatives;
495 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
496 alternatives += string(" ") + i->first.str();
497
4af765b2
LB
498 throw semantic_error(_F("probe point mismatch at position %s (alternatives: %s)",
499 lex_cast(pos).c_str(), alternatives.c_str()), comp->tok);
122b4fcd
JS
500 }
501 }
a477f3f1 502 else if (isglob(loc->components[pos]->functor)) // wildcard?
20c6c071 503 {
a477f3f1
DS
504 match_key match (* loc->components[pos]);
505
828c3ed5
DS
506 // Call find_and_build for each possible match. Ignore errors -
507 // unless we don't find any match.
508 unsigned int num_results = results.size();
b4ceace2
FCE
509 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
510 {
a477f3f1 511 const match_key& subkey = i->first;
828c3ed5 512 match_node* subnode = i->second;
a477f3f1 513
85007c04 514 if (pending_interrupts) break;
49abf162 515
a477f3f1 516 if (match.globmatch(subkey))
828c3ed5 517 {
ddfc759e 518 if (s.verbose > 2)
4af765b2
LB
519 clog << _F("wildcard '%s' matched '%s'",
520 loc->components[pos]->functor.c_str(),
521 subkey.name.c_str()) << endl;
ddfc759e
DS
522
523 // When we have a wildcard, we need to create a copy of
524 // the probe point. Then we'll create a copy of the
525 // wildcard component, and substitute the non-wildcard
526 // functor.
527 probe_point *non_wildcard_pp = new probe_point(*loc);
528 probe_point::component *non_wildcard_component
529 = new probe_point::component(*loc->components[pos]);
530 non_wildcard_component->functor = subkey.name;
531 non_wildcard_pp->components[pos] = non_wildcard_component;
532
5d23847d
FCE
533 // NB: probe conditions are not attached at the wildcard
534 // (component/functor) level, but at the overall
535 // probe_point level.
536
ddfc759e 537 // recurse (with the non-wildcard probe point)
a477f3f1
DS
538 try
539 {
ddfc759e
DS
540 subnode->find_and_build (s, p, non_wildcard_pp, pos+1,
541 results);
a477f3f1
DS
542 }
543 catch (const semantic_error& e)
544 {
545 // Ignore semantic_errors while expanding wildcards.
546 // If we get done and nothing was expanded, the code
547 // following the loop will complain.
ddfc759e
DS
548
549 // If this wildcard didn't match, cleanup.
550 delete non_wildcard_pp;
551 delete non_wildcard_component;
a477f3f1 552 }
828c3ed5 553 }
a477f3f1 554 }
cedd10f4 555 if (! loc->optional && num_results == results.size())
828c3ed5
DS
556 {
557 // We didn't find any wildcard matches (since the size of
558 // the result vector didn't change). Throw an error.
559 string alternatives;
560 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
561 alternatives += string(" ") + i->first.str();
57148ee7 562
4af765b2
LB
563 throw semantic_error(_F("probe point mismatch at position %s %s didn't find any wildcard matches",
564 lex_cast(pos).c_str(),
565 (alternatives == "" ? "" : _(" (alternatives: ") +
566 alternatives + ")").c_str()), loc->components[pos]->tok);
828c3ed5 567 }
b4ceace2 568 }
57148ee7 569 else
20c6c071 570 {
b4ceace2
FCE
571 match_key match (* loc->components[pos]);
572 sub_map_iterator_t i = sub.find (match);
573 if (i == sub.end()) // no match
574 {
575 string alternatives;
576 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
577 alternatives += string(" ") + i->first.str();
57148ee7 578
4af765b2
LB
579 throw semantic_error(_F("probe point mismatch at position %s %s", lex_cast(pos).c_str(),
580 (alternatives == "" ? "" : (_(" (alternatives:") + alternatives +
581 ")").c_str())), loc->components[pos]->tok);
b4ceace2
FCE
582 }
583
584 match_node* subnode = i->second;
585 // recurse
586 subnode->find_and_build (s, p, loc, pos+1, results);
20c6c071
GH
587 }
588}
589
b4ceace2 590
aa30ccd3
FCE
591void
592match_node::build_no_more (systemtap_session& s)
593{
594 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
595 i->second->build_no_more (s);
2531fc1e
FCE
596 for (unsigned k=0; k<ends.size(); k++)
597 {
598 derived_probe_builder *b = ends[k];
599 b->build_no_more (s);
600 }
aa30ccd3
FCE
601}
602
603
20c6c071
GH
604// ------------------------------------------------------------------------
605// Alias probes
606// ------------------------------------------------------------------------
607
c1d5f3f6
FCE
608struct alias_derived_probe: public derived_probe
609{
2c5a19c6
DB
610 alias_derived_probe (probe* base, probe_point *l, const probe_alias *a):
611 derived_probe (base, l), alias(a) {}
c1d5f3f6 612
4af765b2 613 void upchuck () { throw semantic_error (_("inappropriate"), this->tok); }
b20febf3
FCE
614
615 // Alias probes are immediately expanded to other derived_probe
616 // types, and are not themselves emitted or listed in
617 // systemtap_session.probes
dc38c0ae 618
78f6bba6 619 void join_group (systemtap_session&) { upchuck (); }
2c5a19c6
DB
620
621 virtual const probe_alias *get_alias () const { return alias; }
622
623private:
624 const probe_alias *alias; // Used to check for recursion
c1d5f3f6
FCE
625};
626
c72aa911
JS
627probe*
628probe::create_alias(probe_point* l, probe_point* a)
629{
630 vector<probe_point*> aliases(1, a);
631 probe_alias* p = new probe_alias(aliases);
632 p->tok = tok;
633 p->locations.push_back(l);
634 p->body = body;
635 p->privileged = privileged;
636 p->epilogue_style = false;
637 return new alias_derived_probe(this, l, p);
638}
639
c1d5f3f6 640
e2012a7a
DB
641void
642alias_expansion_builder::build(systemtap_session & sess,
643 probe * use,
644 probe_point * location,
645 std::map<std::string, literal *> const &,
646 vector<derived_probe *> & finished_results)
20c6c071 647{
e2012a7a
DB
648 // Don't build the alias expansion if infinite recursion is detected.
649 if (checkForRecursiveExpansion (use)) {
650 stringstream msg;
4af765b2
LB
651 msg << _F("Recursive loop in alias expansion of %s at %s",
652 lex_cast(*location).c_str(), lex_cast(location->components.front()->tok->location).c_str());
e2012a7a
DB
653 // semantic_errors thrown here are ignored.
654 sess.print_error (semantic_error (msg.str()));
655 return;
656 }
57148ee7 657
e2012a7a
DB
658 // We're going to build a new probe and wrap it up in an
659 // alias_expansion_probe so that the expansion loop recognizes it as
660 // such and re-expands its expansion.
20c6c071 661
e2012a7a
DB
662 alias_derived_probe * n = new alias_derived_probe (use, location /* soon overwritten */, this->alias);
663 n->body = new block();
5d23847d 664
e2012a7a
DB
665 // The new probe gets a deep copy of the location list of
666 // the alias (with incoming condition joined)
667 n->locations.clear();
668 for (unsigned i=0; i<alias->locations.size(); i++)
669 {
670 probe_point *pp = new probe_point(*alias->locations[i]);
671 pp->condition = add_condition (pp->condition, location->condition);
672 n->locations.push_back(pp);
673 }
20c6c071 674
e2012a7a
DB
675 // the token location of the alias,
676 n->tok = location->components.front()->tok;
5227f1ea 677
e2012a7a
DB
678 // and statements representing the concatenation of the alias'
679 // body with the use's.
680 //
681 // NB: locals are *not* copied forward, from either alias or
682 // use. The expansion should have its locals re-inferred since
683 // there's concatenated code here and we only want one vardecl per
684 // resulting variable.
57148ee7 685
e2012a7a
DB
686 if (alias->epilogue_style)
687 n->body = new block (use->body, alias->body);
688 else
689 n->body = new block (alias->body, use->body);
a3b4f52c 690
e2012a7a
DB
691 unsigned old_num_results = finished_results.size();
692 derive_probes (sess, n, finished_results, location->optional);
2c5a19c6 693
e2012a7a
DB
694 // Check whether we resolved something. If so, put the
695 // whole library into the queue if not already there.
696 if (finished_results.size() > old_num_results)
697 {
698 stapfile *f = alias->tok->location.file;
699 if (find (sess.files.begin(), sess.files.end(), f)
700 == sess.files.end())
701 sess.files.push_back (f);
2c5a19c6 702 }
e2012a7a
DB
703}
704
705bool
706alias_expansion_builder::checkForRecursiveExpansion (probe *use)
707{
708 // Collect the derivation chain of this probe.
709 vector<probe*>derivations;
710 use->collect_derivation_chain (derivations);
711
712 // Check all probe points in the alias expansion against the currently-being-expanded probe point
713 // of each of the probes in the derivation chain, looking for a match. This
714 // indicates infinite recursion.
715 // The first element of the derivation chain will be the derived_probe representing 'use', so
716 // start the search with the second element.
717 assert (derivations.size() > 0);
718 assert (derivations[0] == use);
719 for (unsigned d = 1; d < derivations.size(); ++d) {
720 if (use->get_alias() == derivations[d]->get_alias())
721 return true; // recursion detected
2c5a19c6 722 }
e2012a7a
DB
723 return false;
724}
20c6c071
GH
725
726
727// ------------------------------------------------------------------------
728// Pattern matching
729// ------------------------------------------------------------------------
730
5227f1ea
GH
731static unsigned max_recursion = 100;
732
57148ee7 733struct
5227f1ea
GH
734recursion_guard
735{
736 unsigned & i;
737 recursion_guard(unsigned & i) : i(i)
738 {
739 if (i > max_recursion)
4af765b2 740 throw semantic_error(_("recursion limit reached"));
5227f1ea
GH
741 ++i;
742 }
57148ee7 743 ~recursion_guard()
5227f1ea
GH
744 {
745 --i;
746 }
747};
748
20c6c071
GH
749// The match-and-expand loop.
750void
b4ceace2
FCE
751derive_probes (systemtap_session& s,
752 probe *p, vector<derived_probe*>& dps,
cedd10f4 753 bool optional)
20c6c071
GH
754{
755 for (unsigned i = 0; i < p->locations.size(); ++i)
756 {
85007c04 757 if (pending_interrupts) break;
49abf162 758
20c6c071 759 probe_point *loc = p->locations[i];
a971b891 760
fe3d01fa
FCE
761 try
762 {
fe3d01fa 763 unsigned num_atbegin = dps.size();
d898100a
FCE
764
765 // Pass down optional flag from e.g. alias reference to each
766 // probe_point instance. We do this by temporarily overriding
767 // the probe_point optional flag. We could instead deep-copy
768 // and set a flag on the copy permanently.
769 bool old_loc_opt = loc->optional;
770 loc->optional = loc->optional || optional;
74efda8d
WH
771 try
772 {
773 s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation!
774 }
775 catch (const semantic_error& e)
776 {
777 if (!loc->optional)
778 throw semantic_error(e);
779 else /* tolerate failure for optional probe */
780 continue;
781 }
782
d898100a 783 loc->optional = old_loc_opt;
fe3d01fa 784 unsigned num_atend = dps.size();
d898100a
FCE
785
786 if (! (loc->optional||optional) && // something required, but
cedd10f4 787 num_atbegin == num_atend) // nothing new derived!
4af765b2 788 throw semantic_error (_("no match"));
d898100a
FCE
789
790 if (loc->sufficient && (num_atend > num_atbegin))
791 {
792 if (s.verbose > 1)
793 {
794 clog << "Probe point ";
795 p->locations[i]->print(clog);
796 clog << " sufficient, skipped";
797 for (unsigned j = i+1; j < p->locations.size(); ++j)
798 {
799 clog << " ";
800 p->locations[j]->print(clog);
801 }
802 clog << endl;
803 }
804 break; // we need not try to derive for any other locations
805 }
fe3d01fa
FCE
806 }
807 catch (const semantic_error& e)
808 {
f3872005
LB
809 //only output in listing if -vv is supplied
810 if (!s.listing_mode || (s.listing_mode && s.verbose > 1))
68ac5d0e
FCE
811 {
812 // XXX: prefer not to print_error at every nest/unroll level
813 semantic_error* er = new semantic_error (e); // copy it
814 stringstream msg;
815 msg << e.msg2;
4af765b2 816 msg << _(" while resolving probe point ") << *loc;
68ac5d0e
FCE
817 er->msg2 = msg.str();
818 s.print_error (* er);
819 delete er;
820 }
fe3d01fa 821 }
a971b891 822
20c6c071
GH
823 }
824}
825
b4ceace2
FCE
826
827
20c6c071 828// ------------------------------------------------------------------------
67c0a579 829//
d02548c0 830// Indexable usage checks
67c0a579
GH
831//
832
d02548c0 833struct symbol_fetcher
07c17d67 834 : public throwing_visitor
67c0a579 835{
d02548c0 836 symbol *&sym;
67c0a579 837
57148ee7 838 symbol_fetcher (symbol *&sym): sym(sym)
67c0a579
GH
839 {}
840
d02548c0
GH
841 void visit_symbol (symbol* e)
842 {
843 sym = e;
844 }
845
b0be9bdb
FCE
846 void visit_target_symbol (target_symbol* e)
847 {
848 sym = e;
849 }
850
d02548c0
GH
851 void visit_arrayindex (arrayindex* e)
852 {
853 e->base->visit_indexable (this);
854 }
855
9b5af295
JS
856 void visit_cast_op (cast_op* e)
857 {
858 sym = e;
859 }
860
d02548c0
GH
861 void throwone (const token* t)
862 {
4af765b2 863 throw semantic_error (_("Expecting symbol or array index expression"), t);
d02548c0
GH
864 }
865};
866
07c17d67 867symbol *
d02548c0
GH
868get_symbol_within_expression (expression *e)
869{
870 symbol *sym = NULL;
871 symbol_fetcher fetcher(sym);
872 e->visit (&fetcher);
b0be9bdb 873 return sym; // NB: may be null!
d02548c0
GH
874}
875
876static symbol *
877get_symbol_within_indexable (indexable *ix)
878{
879 symbol *array = NULL;
880 hist_op *hist = NULL;
881 classify_indexable(ix, array, hist);
882 if (array)
883 return array;
884 else
885 return get_symbol_within_expression (hist->stat);
886}
887
888struct mutated_var_collector
07c17d67 889 : public traversing_visitor
d02548c0
GH
890{
891 set<vardecl *> * mutated_vars;
892
57148ee7 893 mutated_var_collector (set<vardecl *> * mm)
d02548c0
GH
894 : mutated_vars (mm)
895 {}
896
897 void visit_assignment(assignment* e)
898 {
899 if (e->type == pe_stats && e->op == "<<<")
900 {
901 vardecl *vd = get_symbol_within_expression (e->left)->referent;
902 if (vd)
903 mutated_vars->insert (vd);
904 }
1bbeef03 905 traversing_visitor::visit_assignment(e);
d02548c0
GH
906 }
907
67c0a579
GH
908 void visit_arrayindex (arrayindex *e)
909 {
d02548c0
GH
910 if (is_active_lvalue (e))
911 {
912 symbol *sym;
913 if (e->base->is_symbol (sym))
914 mutated_vars->insert (sym->referent);
915 else
4af765b2 916 throw semantic_error(_("Assignment to read-only histogram bucket"), e->tok);
d02548c0 917 }
1bbeef03 918 traversing_visitor::visit_arrayindex (e);
67c0a579
GH
919 }
920};
921
922
d02548c0 923struct no_var_mutation_during_iteration_check
07c17d67 924 : public traversing_visitor
67c0a579
GH
925{
926 systemtap_session & session;
d02548c0
GH
927 map<functiondecl *,set<vardecl *> *> & function_mutates_vars;
928 vector<vardecl *> vars_being_iterated;
57148ee7
FCE
929
930 no_var_mutation_during_iteration_check
67c0a579 931 (systemtap_session & sess,
d02548c0
GH
932 map<functiondecl *,set<vardecl *> *> & fmv)
933 : session(sess), function_mutates_vars (fmv)
67c0a579
GH
934 {}
935
936 void visit_arrayindex (arrayindex *e)
937 {
d7f3e0c5 938 if (is_active_lvalue(e))
67c0a579 939 {
d02548c0
GH
940 vardecl *vd = get_symbol_within_indexable (e->base)->referent;
941 if (vd)
67c0a579 942 {
d02548c0 943 for (unsigned i = 0; i < vars_being_iterated.size(); ++i)
67c0a579 944 {
d02548c0
GH
945 vardecl *v = vars_being_iterated[i];
946 if (v == vd)
947 {
4af765b2
LB
948 string err = _F("variable '%s' modified during 'foreach' iteration",
949 v->name.c_str());
d02548c0
GH
950 session.print_error (semantic_error (err, e->tok));
951 }
67c0a579
GH
952 }
953 }
954 }
1bbeef03 955 traversing_visitor::visit_arrayindex (e);
67c0a579
GH
956 }
957
958 void visit_functioncall (functioncall* e)
959 {
57148ee7 960 map<functiondecl *,set<vardecl *> *>::const_iterator i
d02548c0 961 = function_mutates_vars.find (e->referent);
67c0a579 962
d02548c0 963 if (i != function_mutates_vars.end())
67c0a579 964 {
d02548c0 965 for (unsigned j = 0; j < vars_being_iterated.size(); ++j)
67c0a579 966 {
d02548c0 967 vardecl *m = vars_being_iterated[j];
67c0a579
GH
968 if (i->second->find (m) != i->second->end())
969 {
4af765b2
LB
970 string err = _F("function call modifies var '%s' during 'foreach' iteration",
971 m->name.c_str());
67c0a579
GH
972 session.print_error (semantic_error (err, e->tok));
973 }
974 }
975 }
976
1bbeef03 977 traversing_visitor::visit_functioncall (e);
67c0a579
GH
978 }
979
980 void visit_foreach_loop(foreach_loop* s)
981 {
d02548c0
GH
982 vardecl *vd = get_symbol_within_indexable (s->base)->referent;
983
984 if (vd)
985 vars_being_iterated.push_back (vd);
57148ee7 986
1bbeef03 987 traversing_visitor::visit_foreach_loop (s);
d02548c0
GH
988
989 if (vd)
990 vars_being_iterated.pop_back();
67c0a579
GH
991 }
992};
20c6c071 993
2b066ec1 994
67c0a579
GH
995// ------------------------------------------------------------------------
996
07c17d67
GH
997struct stat_decl_collector
998 : public traversing_visitor
999{
1000 systemtap_session & session;
57148ee7 1001
07c17d67
GH
1002 stat_decl_collector(systemtap_session & sess)
1003 : session(sess)
1004 {}
1005
1006 void visit_stat_op (stat_op* e)
1007 {
1008 symbol *sym = get_symbol_within_expression (e->stat);
1009 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
1010 session.stat_decls[sym->name] = statistic_decl();
1011 }
1012
1013 void visit_assignment (assignment* e)
1014 {
1015 if (e->op == "<<<")
1016 {
1017 symbol *sym = get_symbol_within_expression (e->left);
1018 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
1019 session.stat_decls[sym->name] = statistic_decl();
1020 }
1021 else
1022 traversing_visitor::visit_assignment(e);
1023 }
1024
1025 void visit_hist_op (hist_op* e)
1026 {
1027 symbol *sym = get_symbol_within_expression (e->stat);
1028 statistic_decl new_stat;
1029
1030 if (e->htype == hist_linear)
1031 {
1032 new_stat.type = statistic_decl::linear;
1033 assert (e->params.size() == 3);
1034 new_stat.linear_low = e->params[0];
1035 new_stat.linear_high = e->params[1];
1036 new_stat.linear_step = e->params[2];
1037 }
1038 else
1039 {
1040 assert (e->htype == hist_log);
1041 new_stat.type = statistic_decl::logarithmic;
e38723d2 1042 assert (e->params.size() == 0);
07c17d67
GH
1043 }
1044
1045 map<string, statistic_decl>::iterator i = session.stat_decls.find(sym->name);
1046 if (i == session.stat_decls.end())
1047 session.stat_decls[sym->name] = new_stat;
1048 else
1049 {
1050 statistic_decl & old_stat = i->second;
1051 if (!(old_stat == new_stat))
1052 {
1053 if (old_stat.type == statistic_decl::none)
1054 i->second = new_stat;
1055 else
1056 {
1057 // FIXME: Support multiple co-declared histogram types
4af765b2 1058 semantic_error se(_F("multiple histogram types declared on '%s'", sym->name.c_str()), e->tok);
07c17d67
GH
1059 session.print_error (se);
1060 }
1061 }
57148ee7 1062 }
07c17d67
GH
1063 }
1064
1065};
1066
1067static int
1068semantic_pass_stats (systemtap_session & sess)
1069{
1070 stat_decl_collector sdc(sess);
1071
f76427a2
FCE
1072 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
1073 it->second->body->visit (&sdc);
07c17d67 1074
57148ee7 1075 for (unsigned i = 0; i < sess.probes.size(); ++i)
07c17d67
GH
1076 sess.probes[i]->body->visit (&sdc);
1077
1078 for (unsigned i = 0; i < sess.globals.size(); ++i)
1079 {
1080 vardecl *v = sess.globals[i];
1081 if (v->type == pe_stats)
1082 {
57148ee7 1083
07c17d67
GH
1084 if (sess.stat_decls.find(v->name) == sess.stat_decls.end())
1085 {
4af765b2 1086 semantic_error se(_F("unable to infer statistic parameters for global '%s'", v->name.c_str()));
07c17d67
GH
1087 sess.print_error (se);
1088 }
1089 }
1090 }
57148ee7 1091
7e41d3dc 1092 return sess.num_errors();
07c17d67
GH
1093}
1094
5d23847d
FCE
1095// ------------------------------------------------------------------------
1096
1097// Enforce variable-related invariants: no modification of
1098// a foreach()-iterated array.
1099static int
1100semantic_pass_vars (systemtap_session & sess)
1101{
57148ee7 1102
5d23847d
FCE
1103 map<functiondecl *, set<vardecl *> *> fmv;
1104 no_var_mutation_during_iteration_check chk(sess, fmv);
57148ee7 1105
f76427a2 1106 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
5d23847d 1107 {
f76427a2 1108 functiondecl * fn = it->second;
5d23847d
FCE
1109 if (fn->body)
1110 {
1111 set<vardecl *> * m = new set<vardecl *>();
1112 mutated_var_collector mc (m);
1113 fn->body->visit (&mc);
1114 fmv[fn] = m;
1115 }
1116 }
1117
f76427a2 1118 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
5d23847d 1119 {
f76427a2
FCE
1120 functiondecl * fn = it->second;
1121 if (fn->body) fn->body->visit (&chk);
5d23847d
FCE
1122 }
1123
1124 for (unsigned i = 0; i < sess.probes.size(); ++i)
1125 {
1126 if (sess.probes[i]->body)
1127 sess.probes[i]->body->visit (&chk);
57148ee7 1128 }
5d23847d
FCE
1129
1130 return sess.num_errors();
1131}
1132
1133
1134// ------------------------------------------------------------------------
1135
1136// Rewrite probe condition expressions into probe bodies. Tricky and
1137// exciting business, this. This:
1138//
1139// probe foo if (g1 || g2) { ... }
1140// probe bar { ... g1 ++ ... }
1141//
1142// becomes:
1143//
1144// probe begin(MAX) { if (! (g1 || g2)) %{ disable_probe_foo %} }
1145// probe foo { if (! (g1 || g2)) next; ... }
57148ee7 1146// probe bar { ... g1 ++ ...;
5d23847d
FCE
1147// if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %}
1148// }
1149//
1150// XXX: As a first cut, do only the "inline probe condition" part of the
1151// transform.
1152
1153static int
1154semantic_pass_conditions (systemtap_session & sess)
1155{
1156 for (unsigned i = 0; i < sess.probes.size(); ++i)
1157 {
1158 derived_probe* p = sess.probes[i];
1159 expression* e = p->sole_location()->condition;
1160 if (e)
1161 {
313db8e6 1162 varuse_collecting_visitor vut(sess);
5d23847d
FCE
1163 e->visit (& vut);
1164
1165 if (! vut.written.empty())
1166 {
4af765b2 1167 string err = (_("probe condition must not modify any variables"));
5d23847d
FCE
1168 sess.print_error (semantic_error (err, e->tok));
1169 }
1170 else if (vut.embedded_seen)
1171 {
4af765b2 1172 sess.print_error (semantic_error (_("probe condition must not include impure embedded-C"), e->tok));
5d23847d
FCE
1173 }
1174
1175 // Add the condition expression to the front of the
1176 // derived_probe body.
1177 if_statement *ifs = new if_statement ();
1178 ifs->tok = e->tok;
1179 ifs->thenblock = new next_statement ();
1180 ifs->thenblock->tok = e->tok;
1181 ifs->elseblock = NULL;
1182 unary_expression *notex = new unary_expression ();
1183 notex->op = "!";
1184 notex->tok = e->tok;
1185 notex->operand = e;
1186 ifs->condition = notex;
ba6f838d 1187 p->body = new block (ifs, p->body);
5d23847d 1188 }
57148ee7 1189 }
5d23847d
FCE
1190
1191 return sess.num_errors();
1192}
1193
ac9ca50a
MW
1194// ------------------------------------------------------------------------
1195
1196
1197// Simple visitor that just goes through all embedded code blocks that
1198// are available at the end all the optimizations to register any
1199// relevant pragmas or other indicators found, so that session flags can
1200// be set that can be inspected at translation time to trigger any
1201// necessary initialization of code needed by the embedded code functions.
1202
1203// This is only for pragmas that don't have any other side-effect than
1204// needing some initialization at module init time. Currently only handles
1205// /* pragma:vma */.
1206
1207// /* pragma:uprobes */ is handled during the typeresolution_info pass.
2363d2a5
DB
1208// /* pure */, /* unprivileged */. /* myproc-unprivileged */ and /* guru */
1209// are handled by the varuse_collecting_visitor.
ac9ca50a
MW
1210
1211struct embeddedcode_info: public functioncall_traversing_visitor
1212{
1213protected:
1214 systemtap_session& session;
1215
1216public:
1217 embeddedcode_info (systemtap_session& s): session(s) { }
1218
1219 void visit_embeddedcode (embeddedcode* c)
1220 {
a057c85c 1221 if (! vma_tracker_enabled(session)
ac9ca50a
MW
1222 && c->code.find("/* pragma:vma */") != string::npos)
1223 {
a057c85c 1224 enable_vma_tracker(session);
ac9ca50a 1225 if (session.verbose > 2)
4af765b2
LB
1226 clog << _F("Turning on task_finder vma_tracker, pragma:vma found in %s",
1227 current_function->name.c_str()) << endl;
ac9ca50a
MW
1228 }
1229 }
1230};
1231
1232void embeddedcode_info_pass (systemtap_session& s)
1233{
1234 embeddedcode_info eci (s);
1235 for (unsigned i=0; i<s.probes.size(); i++)
1236 s.probes[i]->body->visit (& eci);
1237}
5d23847d 1238
07c17d67
GH
1239// ------------------------------------------------------------------------
1240
2b066ec1
FCE
1241
1242static int semantic_pass_symbols (systemtap_session&);
c214bd6a
DS
1243static int semantic_pass_optimize1 (systemtap_session&);
1244static int semantic_pass_optimize2 (systemtap_session&);
2b066ec1 1245static int semantic_pass_types (systemtap_session&);
d02548c0 1246static int semantic_pass_vars (systemtap_session&);
07c17d67 1247static int semantic_pass_stats (systemtap_session&);
5d23847d 1248static int semantic_pass_conditions (systemtap_session&);
2b066ec1
FCE
1249
1250
1251// Link up symbols to their declarations. Set the session's
1252// files/probes/functions/globals vectors from the transitively
1253// reached set of stapfiles in s.library_files, starting from
20c6c071 1254// s.user_file. Perform automatic tapset inclusion and probe
2b066ec1
FCE
1255// alias expansion.
1256static int
1257semantic_pass_symbols (systemtap_session& s)
1258{
1259 symresolution_info sym (s);
1260
1261 // NB: s.files can grow during this iteration, so size() can
1262 // return gradually increasing numbers.
1263 s.files.push_back (s.user_file);
1264 for (unsigned i = 0; i < s.files.size(); i++)
1265 {
85007c04 1266 if (pending_interrupts) break;
2b066ec1
FCE
1267 stapfile* dome = s.files[i];
1268
1269 // Pass 1: add globals and functions to systemtap-session master list,
1270 // so the find_* functions find them
1271
1272 for (unsigned i=0; i<dome->globals.size(); i++)
1273 s.globals.push_back (dome->globals[i]);
1274
1275 for (unsigned i=0; i<dome->functions.size(); i++)
f76427a2 1276 s.functions[dome->functions[i]->name] = dome->functions[i];
2b066ec1 1277
54dfabe9
FCE
1278 for (unsigned i=0; i<dome->embeds.size(); i++)
1279 s.embeds.push_back (dome->embeds[i]);
1280
f8809d54 1281 // Pass 2: derive probes and resolve any further symbols in the
57148ee7 1282 // derived results.
2b066ec1
FCE
1283
1284 for (unsigned i=0; i<dome->probes.size(); i++)
1285 {
85007c04 1286 if (pending_interrupts) break;
2b066ec1
FCE
1287 probe* p = dome->probes [i];
1288 vector<derived_probe*> dps;
1289
a971b891
FCE
1290 // much magic happens here: probe alias expansion, wildcard
1291 // matching, low-level derived_probe construction.
b4ceace2 1292 derive_probes (s, p, dps);
2b066ec1
FCE
1293
1294 for (unsigned j=0; j<dps.size(); j++)
1295 {
85007c04 1296 if (pending_interrupts) break;
2b066ec1 1297 derived_probe* dp = dps[j];
b20febf3
FCE
1298 s.probes.push_back (dp);
1299 dp->join_group (s);
2b066ec1 1300
57148ee7 1301 try
2b066ec1 1302 {
f80d9004 1303 for (unsigned k=0; k<s.code_filters.size(); k++)
8b095b45 1304 s.code_filters[k]->replace (dp->body);
f80d9004 1305
2b066ec1 1306 sym.current_function = 0;
5227f1ea 1307 sym.current_probe = dp;
2b066ec1 1308 dp->body->visit (& sym);
5d23847d
FCE
1309
1310 // Process the probe-point condition expression.
1311 sym.current_function = 0;
1312 sym.current_probe = 0;
1313 if (dp->sole_location()->condition)
1314 dp->sole_location()->condition->visit (& sym);
2b066ec1
FCE
1315 }
1316 catch (const semantic_error& e)
1317 {
1318 s.print_error (e);
1319 }
1320 }
1321 }
f8809d54
JS
1322
1323 // Pass 3: process functions
1324
1325 for (unsigned i=0; i<dome->functions.size(); i++)
1326 {
1327 if (pending_interrupts) break;
1328 functiondecl* fd = dome->functions[i];
1329
1330 try
1331 {
1332 for (unsigned j=0; j<s.code_filters.size(); j++)
1333 s.code_filters[j]->replace (fd->body);
1334
1335 sym.current_function = fd;
1336 sym.current_probe = 0;
1337 fd->body->visit (& sym);
1338 }
1339 catch (const semantic_error& e)
1340 {
1341 s.print_error (e);
1342 }
1343 }
2b066ec1 1344 }
aa30ccd3
FCE
1345
1346 // Inform all derived_probe builders that we're done with
1347 // all resolution, so it's time to release caches.
1348 s.pattern_root->build_no_more (s);
57148ee7 1349
a07a2c28
LB
1350 if(s.systemtap_v_check){
1351 for(unsigned i=0;i<s.globals.size();i++){
1352 if(s.globals[i]->systemtap_v_conditional)
4af765b2 1353 s.print_warning(_("This global uses tapset constructs that are dependent on systemtap version"), s.globals[i]->tok);
a07a2c28
LB
1354 }
1355
1356 for(map<string, functiondecl*>::const_iterator i=s.functions.begin();i != s.functions.end();++i){
1357 if(i->second->systemtap_v_conditional)
4af765b2 1358 s.print_warning(_("This function uses tapset constructs that are dependent on systemtap version"), i->second->tok);
a07a2c28
LB
1359 }
1360
1361 for(unsigned i=0;i<s.probes.size();i++){
1362 vector<probe*> sysvc;
1363 s.probes[i]->collect_derivation_chain(sysvc);
1364 for(unsigned j=0;j<sysvc.size();j++){
1365 if(sysvc[j]->systemtap_v_conditional)
4af765b2 1366 s.print_warning(_("This probe uses tapset constructs that are dependent on systemtap version"), sysvc[j]->tok);
a07a2c28 1367 if(sysvc[j]->get_alias() && sysvc[j]->get_alias()->systemtap_v_conditional)
4af765b2 1368 s.print_warning(_("This alias uses tapset constructs that are dependent on systemtap version"), sysvc[j]->get_alias()->tok);
a07a2c28
LB
1369 }
1370 }
1371 }
1372
7e41d3dc 1373 return s.num_errors(); // all those print_error calls
2b066ec1
FCE
1374}
1375
1376
30263a73 1377
0a102c82
SC
1378// Keep unread global variables for probe end value display.
1379void add_global_var_display (systemtap_session& s)
1380{
5ae31731
FCE
1381 // Don't generate synthetic end probes when in listings mode;
1382 // it would clutter up the list of probe points with "end ...".
1383 if (s.listing_mode) return;
3438f38f 1384
313db8e6 1385 varuse_collecting_visitor vut(s);
9d8a6ba3 1386
0a102c82
SC
1387 for (unsigned i=0; i<s.probes.size(); i++)
1388 {
1389 s.probes[i]->body->visit (& vut);
1390
1391 if (s.probes[i]->sole_location()->condition)
1392 s.probes[i]->sole_location()->condition->visit (& vut);
1393 }
1394
1395 for (unsigned g=0; g < s.globals.size(); g++)
1396 {
1397 vardecl* l = s.globals[g];
9d8a6ba3
SC
1398 if ((vut.read.find (l) != vut.read.end()
1399 && vut.used.find (l) != vut.used.end())
e491a713 1400 || vut.written.find (l) == vut.written.end())
0a102c82
SC
1401 continue;
1402
b5852334 1403 // Don't generate synthetic end probes for unread globals
5ae31731
FCE
1404 // declared only within tapsets. (RHBZ 468139), but rather
1405 // only within the end-user script.
1406
7584f162
RA
1407 bool tapset_global = false;
1408 for (size_t m=0; m < s.library_files.size(); m++)
1409 {
1410 for (size_t n=0; n < s.library_files[m]->globals.size(); n++)
1411 {
1412 if (l->name == s.library_files[m]->globals[n]->name)
1413 {tapset_global = true; break;}
1414 }
1415 }
1416 if (tapset_global)
1417 continue;
5ae31731 1418
0a102c82 1419 probe_point::component* c = new probe_point::component("end");
d5e178c1
JS
1420 probe_point* pl = new probe_point;
1421 pl->components.push_back (c);
1422
0a102c82 1423 vector<derived_probe*> dps;
6d2685fe 1424 block *b = new block;
ead25cf5 1425 b->tok = l->tok;
0a102c82 1426
d5e178c1 1427 probe* p = new probe;
db48cbe9 1428 p->tok = l->tok;
0a102c82 1429 p->locations.push_back (pl);
0a102c82
SC
1430
1431 // Create a symbol
1432 symbol* g_sym = new symbol;
1433 g_sym->name = l->name;
1434 g_sym->tok = l->tok;
1435 g_sym->type = l->type;
57148ee7 1436 g_sym->referent = l;
0a102c82 1437
ead25cf5 1438 token* print_tok = new token(*l->tok);
d5e178c1
JS
1439 print_tok->type = tok_identifier;
1440 print_tok->content = "printf";
1441
1442 print_format* pf = print_format::create(print_tok);
0a102c82 1443 pf->raw_components += l->name;
0a102c82
SC
1444
1445 if (l->index_types.size() == 0) // Scalar
1446 {
e071e49b 1447 if (l->type == pe_stats)
49060244
WC
1448 if (strverscmp(s.compatible.c_str(), "1.4") >= 0)
1449 pf->raw_components += " @count=%#d @min=%#d @max=%#d @sum=%#d @avg=%#d\\n";
1450 else
1451 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
e071e49b 1452 else if (l->type == pe_string)
0a102c82
SC
1453 pf->raw_components += "=\"%#s\"\\n";
1454 else
1455 pf->raw_components += "=%#x\\n";
0a102c82
SC
1456 pf->components = print_format::string_to_components(pf->raw_components);
1457 expr_statement* feb = new expr_statement;
1458 feb->value = pf;
1459 feb->tok = print_tok;
e071e49b
SC
1460 if (l->type == pe_stats)
1461 {
1462 struct stat_op* so [5];
1463 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
1464
1465 for (unsigned si = 0;
1466 si < (sizeof(so)/sizeof(struct stat_op*));
1467 si++)
1468 {
1469 so[si]= new stat_op;
1470 so[si]->ctype = stypes[si];
1471 so[si]->type = pe_long;
1472 so[si]->stat = g_sym;
1473 so[si]->tok = l->tok;
1474 pf->args.push_back(so[si]);
1475 }
1476 }
1477 else
1478 pf->args.push_back(g_sym);
271d408e
WH
1479
1480 /* PR7053: Checking empty aggregate for global variable */
1481 if (l->type == pe_stats) {
1482 stat_op *so= new stat_op;
1483 so->ctype = sc_count;
1484 so->type = pe_long;
1485 so->stat = g_sym;
1486 so->tok = l->tok;
1487 comparison *be = new comparison;
1488 be->op = ">";
1489 be->tok = l->tok;
1490 be->left = so;
1491 be->right = new literal_number(0);
1492
1493 /* Create printf @count=0x0 in else block */
d5e178c1 1494 print_format* pf_0 = print_format::create(print_tok);
271d408e
WH
1495 pf_0->raw_components += l->name;
1496 pf_0->raw_components += " @count=0x0\\n";
271d408e
WH
1497 pf_0->components = print_format::string_to_components(pf_0->raw_components);
1498 expr_statement* feb_else = new expr_statement;
1499 feb_else->value = pf_0;
1500 feb_else->tok = print_tok;
1501 if_statement *ifs = new if_statement;
1502 ifs->tok = l->tok;
1503 ifs->condition = be;
1504 ifs->thenblock = feb ;
1505 ifs->elseblock = feb_else;
1506 b->statements.push_back(ifs);
1507 }
1508 else /* other non-stat cases */
1509 b->statements.push_back(feb);
0a102c82
SC
1510 }
1511 else // Array
1512 {
1513 int idx_count = l->index_types.size();
0a102c82
SC
1514 symbol* idx_sym[idx_count];
1515 vardecl* idx_v[idx_count];
1516 // Create a foreach loop
0a102c82 1517 foreach_loop* fe = new foreach_loop;
e91b23bc
FCE
1518 fe->sort_direction = -1; // imply decreasing sort on value
1519 fe->sort_column = 0; // as in foreach ([a,b,c] in array-) { }
c261711d 1520 fe->value = NULL;
0a102c82 1521 fe->limit = NULL;
ead25cf5 1522 fe->tok = l->tok;
0a102c82
SC
1523
1524 // Create indices for the foreach loop
1525 for (int i=0; i < idx_count; i++)
1526 {
0a102c82
SC
1527 char *idx_name;
1528 if (asprintf (&idx_name, "idx%d", i) < 0)
1529 return;
0a102c82 1530 idx_sym[i] = new symbol;
0a102c82 1531 idx_sym[i]->name = idx_name;
db48cbe9 1532 idx_sym[i]->tok = l->tok;
0a102c82
SC
1533 idx_v[i] = new vardecl;
1534 idx_v[i]->name = idx_name;
0a102c82 1535 idx_v[i]->type = l->index_types[i];
db48cbe9 1536 idx_v[i]->tok = l->tok;
0a102c82
SC
1537 idx_sym[i]->referent = idx_v[i];
1538 fe->indexes.push_back (idx_sym[i]);
1539 }
1540
1541 // Create a printf for the foreach loop
ead25cf5 1542 pf->raw_components += "[";
0a102c82 1543 for (int i=0; i < idx_count; i++)
ead25cf5
JS
1544 {
1545 if (i > 0)
1546 pf->raw_components += ",";
1547 if (l->index_types[i] == pe_string)
1548 pf->raw_components += "\"%#s\"";
1549 else
1550 pf->raw_components += "%#d";
1551 }
1552 pf->raw_components += "]";
e491a713 1553 if (l->type == pe_stats)
49060244
WC
1554 if (strverscmp(s.compatible.c_str(), "1.4") >= 0)
1555 pf->raw_components += " @count=%#d @min=%#d @max=%#d @sum=%#d @avg=%#d\\n";
1556 else
1557 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
e491a713 1558 else if (l->type == pe_string)
0a102c82
SC
1559 pf->raw_components += "=\"%#s\"\\n";
1560 else
1561 pf->raw_components += "=%#x\\n";
1562
1563 // Create an index for the array
1564 struct arrayindex* ai = new arrayindex;
1565 ai->tok = l->tok;
1566 ai->base = g_sym;
e491a713 1567
0a102c82
SC
1568 for (int i=0; i < idx_count; i++)
1569 {
1570 ai->indexes.push_back (idx_sym[i]);
1571 pf->args.push_back(idx_sym[i]);
1572 }
e491a713
SC
1573 if (l->type == pe_stats)
1574 {
1575 struct stat_op* so [5];
e491a713 1576 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
e071e49b
SC
1577
1578 ai->type = pe_stats;
db48cbe9
SC
1579 for (unsigned si = 0;
1580 si < (sizeof(so)/sizeof(struct stat_op*));
1581 si++)
e491a713
SC
1582 {
1583 so[si]= new stat_op;
1584 so[si]->ctype = stypes[si];
1585 so[si]->type = pe_long;
1586 so[si]->stat = ai;
db48cbe9 1587 so[si]->tok = l->tok;
e071e49b 1588 pf->args.push_back(so[si]);
e491a713 1589 }
e491a713
SC
1590 }
1591 else
c261711d
JS
1592 {
1593 // Create value for the foreach loop
1594 fe->value = new symbol;
1595 fe->value->name = "val";
1596 fe->value->tok = l->tok;
1597 pf->args.push_back(fe->value);
1598 }
57148ee7 1599
0a102c82
SC
1600 pf->components = print_format::string_to_components(pf->raw_components);
1601 expr_statement* feb = new expr_statement;
1602 feb->value = pf;
ead25cf5 1603 feb->tok = l->tok;
0a102c82
SC
1604 fe->base = g_sym;
1605 fe->block = (statement*)feb;
1606 b->statements.push_back(fe);
0a102c82
SC
1607 }
1608
0a102c82 1609 // Add created probe
6d2685fe
SC
1610 p->body = b;
1611 derive_probes (s, p, dps);
0a102c82
SC
1612 for (unsigned i = 0; i < dps.size(); i++)
1613 {
1614 derived_probe* dp = dps[i];
1615 s.probes.push_back (dp);
1616 dp->join_group (s);
1617 }
6d2685fe
SC
1618 // Repopulate symbol and type info
1619 symresolution_info sym (s);
1620 sym.current_function = 0;
1621 sym.current_probe = dps[0];
1622 dps[0]->body->visit (& sym);
0a102c82 1623
6d2685fe
SC
1624 semantic_pass_types(s);
1625 // Mark that variable is read
0a102c82
SC
1626 vut.read.insert (l);
1627 }
1628}
2b066ec1
FCE
1629
1630int
1631semantic_pass (systemtap_session& s)
1632{
59bafbe8 1633 int rc = 0;
20c6c071 1634
57148ee7 1635 try
59bafbe8
FCE
1636 {
1637 s.register_library_aliases();
1638 register_standard_tapsets(s);
57148ee7 1639
5d23847d
FCE
1640 if (rc == 0) rc = semantic_pass_symbols (s);
1641 if (rc == 0) rc = semantic_pass_conditions (s);
c0f56268 1642 if (rc == 0) rc = semantic_pass_optimize1 (s);
59bafbe8 1643 if (rc == 0) rc = semantic_pass_types (s);
0a102c82 1644 if (rc == 0) add_global_var_display (s);
c0f56268 1645 if (rc == 0) rc = semantic_pass_optimize2 (s);
d02548c0 1646 if (rc == 0) rc = semantic_pass_vars (s);
07c17d67 1647 if (rc == 0) rc = semantic_pass_stats (s);
7b8548ee 1648 if (rc == 0) embeddedcode_info_pass (s);
57148ee7 1649
8c938ec7 1650 if (s.num_errors() == 0 && s.probes.size() == 0 && !s.listing_mode)
4af765b2 1651 throw semantic_error (_("no probes found"));
59bafbe8
FCE
1652 }
1653 catch (const semantic_error& e)
1654 {
1655 s.print_error (e);
21beacc9 1656 rc ++;
59bafbe8 1657 }
57148ee7 1658
f119a57f
FCE
1659 // PR11443
1660 if (s.listing_mode && s.probes.size() == 0)
1661 rc ++;
1662
2b066ec1
FCE
1663 return rc;
1664}
1665
1666
2b066ec1
FCE
1667// ------------------------------------------------------------------------
1668// semantic processing: symbol resolution
1669
1670
1671symresolution_info::symresolution_info (systemtap_session& s):
5227f1ea 1672 session (s), current_function (0), current_probe (0)
2b066ec1
FCE
1673{
1674}
1675
1676
1677void
1678symresolution_info::visit_block (block* e)
1679{
1680 for (unsigned i=0; i<e->statements.size(); i++)
1681 {
57148ee7 1682 try
2b066ec1
FCE
1683 {
1684 e->statements[i]->visit (this);
1685 }
1686 catch (const semantic_error& e)
1687 {
1688 session.print_error (e);
1689 }
1690 }
1691}
1692
1693
69c68955
FCE
1694void
1695symresolution_info::visit_foreach_loop (foreach_loop* e)
1696{
1697 for (unsigned i=0; i<e->indexes.size(); i++)
1698 e->indexes[i]->visit (this);
1699
57148ee7 1700 symbol *array = NULL;
d02548c0
GH
1701 hist_op *hist = NULL;
1702 classify_indexable (e->base, array, hist);
69c68955 1703
d02548c0
GH
1704 if (array)
1705 {
1706 if (!array->referent)
57148ee7 1707 {
2e526dab 1708 vardecl* d = find_var (array->name, e->indexes.size (), array->tok);
d02548c0
GH
1709 if (d)
1710 array->referent = d;
1711 else
60bebf58
JS
1712 {
1713 stringstream msg;
4af765b2
LB
1714 msg << _F("unresolved arity-%zu global array %s, missing global declaration?",
1715 e->indexes.size(), array->name.c_str());
60bebf58
JS
1716 throw semantic_error (msg.str(), e->tok);
1717 }
d02548c0
GH
1718 }
1719 }
57148ee7 1720 else
d02548c0
GH
1721 {
1722 assert (hist);
1723 hist->visit (this);
1724 }
69c68955 1725
c261711d
JS
1726 if (e->value)
1727 e->value->visit (this);
1728
27f21e8c
DS
1729 if (e->limit)
1730 e->limit->visit (this);
1731
69c68955
FCE
1732 e->block->visit (this);
1733}
1734
d02548c0 1735
57148ee7 1736struct
d98d459c
GH
1737delete_statement_symresolution_info:
1738 public traversing_visitor
1739{
1740 symresolution_info *parent;
1741
1742 delete_statement_symresolution_info (symresolution_info *p):
1743 parent(p)
1744 {}
1745
1746 void visit_arrayindex (arrayindex* e)
1747 {
1748 parent->visit_arrayindex (e);
1749 }
1750 void visit_functioncall (functioncall* e)
1751 {
1752 parent->visit_functioncall (e);
1753 }
1754
1755 void visit_symbol (symbol* e)
1756 {
1757 if (e->referent)
1758 return;
57148ee7 1759
2e526dab 1760 vardecl* d = parent->find_var (e->name, -1, e->tok);
d98d459c
GH
1761 if (d)
1762 e->referent = d;
1763 else
4af765b2 1764 throw semantic_error (_("unresolved array in delete statement"), e->tok);
d98d459c
GH
1765 }
1766};
1767
57148ee7 1768void
d98d459c
GH
1769symresolution_info::visit_delete_statement (delete_statement* s)
1770{
1771 delete_statement_symresolution_info di (this);
1772 s->value->visit (&di);
1773}
1774
69c68955 1775
2b066ec1
FCE
1776void
1777symresolution_info::visit_symbol (symbol* e)
1778{
1779 if (e->referent)
1780 return;
1781
2e526dab 1782 vardecl* d = find_var (e->name, 0, e->tok);
2b066ec1
FCE
1783 if (d)
1784 e->referent = d;
1785 else
1786 {
1787 // new local
1788 vardecl* v = new vardecl;
1789 v->name = e->name;
1790 v->tok = e->tok;
58701b78 1791 v->set_arity(0, e->tok);
2b066ec1
FCE
1792 if (current_function)
1793 current_function->locals.push_back (v);
1794 else if (current_probe)
1795 current_probe->locals.push_back (v);
1796 else
5d23847d 1797 // must be probe-condition expression
4af765b2 1798 throw semantic_error (_("probe condition must not reference undeclared global"), e->tok);
2b066ec1
FCE
1799 e->referent = v;
1800 }
1801}
1802
1803
1804void
1805symresolution_info::visit_arrayindex (arrayindex* e)
1806{
1807 for (unsigned i=0; i<e->indexes.size(); i++)
1808 e->indexes[i]->visit (this);
1809
57148ee7 1810 symbol *array = NULL;
d02548c0
GH
1811 hist_op *hist = NULL;
1812 classify_indexable(e->base, array, hist);
2b066ec1 1813
d02548c0 1814 if (array)
313b2f74 1815 {
d02548c0
GH
1816 if (array->referent)
1817 return;
1818
2e526dab 1819 vardecl* d = find_var (array->name, e->indexes.size (), array->tok);
d02548c0
GH
1820 if (d)
1821 array->referent = d;
313b2f74 1822 else
d02548c0 1823 {
60bebf58 1824 stringstream msg;
4af765b2
LB
1825 msg << _F("unresolved arity-%zu global array %s, missing global declaration?",
1826 e->indexes.size(), array->name.c_str());
60bebf58 1827 throw semantic_error (msg.str(), e->tok);
57148ee7 1828 }
d02548c0
GH
1829 }
1830 else
1831 {
1832 assert (hist);
1833 hist->visit (this);
313b2f74 1834 }
2b066ec1
FCE
1835}
1836
1837
1838void
1839symresolution_info::visit_functioncall (functioncall* e)
1840{
5d23847d
FCE
1841 // XXX: we could relax this, if we're going to examine the
1842 // vartracking data recursively. See testsuite/semko/fortytwo.stp.
1843 if (! (current_function || current_probe))
1844 {
1845 // must be probe-condition expression
4af765b2 1846 throw semantic_error (_("probe condition must not reference function"), e->tok);
5d23847d
FCE
1847 }
1848
2b066ec1
FCE
1849 for (unsigned i=0; i<e->args.size(); i++)
1850 e->args[i]->visit (this);
1851
1852 if (e->referent)
1853 return;
1854
1855 functiondecl* d = find_function (e->function, e->args.size ());
1856 if (d)
1857 e->referent = d;
1858 else
2a99f48f 1859 {
7e41d3dc 1860 stringstream msg;
4af765b2 1861 msg << _F("unresolved arity-%zu function", e->args.size());
7e41d3dc 1862 throw semantic_error (msg.str(), e->tok);
2a99f48f 1863 }
2b066ec1
FCE
1864}
1865
a07a2c28
LB
1866/*find_var will return an argument other than zero if the name matches the var
1867 * name ie, if the current local name matches the name passed to find_var*/
57148ee7 1868vardecl*
2e526dab 1869symresolution_info::find_var (const string& name, int arity, const token* tok)
2b066ec1 1870{
5d23847d
FCE
1871 if (current_function || current_probe)
1872 {
1873 // search locals
57148ee7 1874 vector<vardecl*>& locals = (current_function ?
5d23847d
FCE
1875 current_function->locals :
1876 current_probe->locals);
57148ee7
FCE
1877
1878
5d23847d 1879 for (unsigned i=0; i<locals.size(); i++)
60bebf58 1880 if (locals[i]->name == name)
5d23847d 1881 {
58701b78 1882 locals[i]->set_arity (arity, tok);
5d23847d
FCE
1883 return locals[i];
1884 }
1885 }
2b066ec1 1886
313b2f74
GH
1887 // search function formal parameters (for scalars)
1888 if (arity == 0 && current_function)
2b066ec1
FCE
1889 for (unsigned i=0; i<current_function->formal_args.size(); i++)
1890 if (current_function->formal_args[i]->name == name)
8846477c
FCE
1891 {
1892 // NB: no need to check arity here: formal args always scalar
58701b78 1893 current_function->formal_args[i]->set_arity (0, tok);
8846477c
FCE
1894 return current_function->formal_args[i];
1895 }
2b066ec1 1896
313b2f74 1897 // search processed globals
2b066ec1 1898 for (unsigned i=0; i<session.globals.size(); i++)
60bebf58 1899 if (session.globals[i]->name == name)
8846477c 1900 {
58701b78 1901 session.globals[i]->set_arity (arity, tok);
2e526dab
FCE
1902 if (! session.suppress_warnings)
1903 {
1904 vardecl* v = session.globals[i];
1905 // clog << "resolved " << *tok << " to global " << *v->tok << endl;
1906 if (v->tok->location.file != tok->location.file)
1907 {
4af765b2
LB
1908 session.print_warning (_F("cross-file global variable reference to %s from",
1909 lex_cast(*v->tok).c_str()), tok);
2e526dab
FCE
1910 }
1911 }
8846477c
FCE
1912 return session.globals[i];
1913 }
57148ee7 1914
2b066ec1
FCE
1915 // search library globals
1916 for (unsigned i=0; i<session.library_files.size(); i++)
1917 {
1918 stapfile* f = session.library_files[i];
1919 for (unsigned j=0; j<f->globals.size(); j++)
84e5ea0f
FCE
1920 {
1921 vardecl* g = f->globals[j];
60bebf58 1922 if (g->name == name)
84e5ea0f 1923 {
58701b78 1924 g->set_arity (arity, tok);
57148ee7
FCE
1925
1926 // put library into the queue if not already there
1927 if (find (session.files.begin(), session.files.end(), f)
84e5ea0f
FCE
1928 == session.files.end())
1929 session.files.push_back (f);
57148ee7 1930
84e5ea0f
FCE
1931 return g;
1932 }
1933 }
2b066ec1
FCE
1934 }
1935
2b066ec1 1936 return 0;
2b066ec1
FCE
1937}
1938
1939
57148ee7 1940functiondecl*
2b066ec1
FCE
1941symresolution_info::find_function (const string& name, unsigned arity)
1942{
f76427a2
FCE
1943 // the common path
1944 if (session.functions.find(name) != session.functions.end())
2b066ec1 1945 {
f76427a2
FCE
1946 functiondecl* fd = session.functions[name];
1947 assert (fd->name == name);
1948 if (fd->formal_args.size() == arity)
2b066ec1
FCE
1949 return fd;
1950 }
1951
1952 // search library globals
1953 for (unsigned i=0; i<session.library_files.size(); i++)
1954 {
1955 stapfile* f = session.library_files[i];
1956 for (unsigned j=0; j<f->functions.size(); j++)
1957 if (f->functions[j]->name == name &&
1958 f->functions[j]->formal_args.size() == arity)
1959 {
1960 // put library into the queue if not already there
1961 if (0) // session.verbose_resolution
4af765b2
LB
1962 cerr << _F(" function %s is defined from %s",
1963 name.c_str(), f->name.c_str()) << endl;
2b066ec1 1964
57148ee7 1965 if (find (session.files.begin(), session.files.end(), f)
2b066ec1
FCE
1966 == session.files.end())
1967 session.files.push_back (f);
1968 // else .. print different message?
1969
1970 return f->functions[j];
1971 }
1972 }
1973
1974 return 0;
2b066ec1
FCE
1975}
1976
1977
cbfbbf69
FCE
1978
1979// ------------------------------------------------------------------------
1980// optimization
1981
1982
1983// Do away with functiondecls that are never (transitively) called
1984// from probes.
1985void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
1986{
1987 functioncall_traversing_visitor ftv;
1988 for (unsigned i=0; i<s.probes.size(); i++)
5d23847d
FCE
1989 {
1990 s.probes[i]->body->visit (& ftv);
1991 if (s.probes[i]->sole_location()->condition)
1992 s.probes[i]->sole_location()->condition->visit (& ftv);
1993 }
f76427a2
FCE
1994 vector<functiondecl*> new_unused_functions;
1995 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
cbfbbf69 1996 {
f76427a2
FCE
1997 functiondecl* fd = it->second;
1998 if (ftv.traversed.find(fd) == ftv.traversed.end())
cbfbbf69 1999 {
2203b032 2000 if (fd->tok->location.file->name == s.user_file->name && // !tapset
59de45f1 2001 ! s.suppress_warnings && ! fd->synthetic)
4af765b2 2002 s.print_warning (_F("Eliding unused function '%s'", fd->name.c_str()), fd->tok);
a9e8f7e0 2003 else if (s.verbose>2)
4af765b2 2004 clog << _F("Eliding unused function '%s'", fd->name.c_str()) << endl;
f76427a2
FCE
2005 // s.functions.erase (it); // NB: can't, since we're already iterating upon it
2006 new_unused_functions.push_back (fd);
cbfbbf69 2007 relaxed_p = false;
cbfbbf69 2008 }
f76427a2
FCE
2009 }
2010 for (unsigned i=0; i<new_unused_functions.size(); i++)
2011 {
2012 map<string,functiondecl*>::iterator where = s.functions.find (new_unused_functions[i]->name);
2013 assert (where != s.functions.end());
2014 s.functions.erase (where);
2015 if (s.tapset_compile_coverage)
2016 s.unused_functions.push_back (new_unused_functions[i]);
cbfbbf69
FCE
2017 }
2018}
2019
2020
2021// ------------------------------------------------------------------------
2022
2023// Do away with local & global variables that are never
2024// written nor read.
cfd621bc 2025void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations)
cbfbbf69 2026{
313db8e6 2027 varuse_collecting_visitor vut(s);
cfd621bc 2028
cbfbbf69 2029 for (unsigned i=0; i<s.probes.size(); i++)
5d23847d
FCE
2030 {
2031 s.probes[i]->body->visit (& vut);
2032
2033 if (s.probes[i]->sole_location()->condition)
2034 s.probes[i]->sole_location()->condition->visit (& vut);
2035 }
2036
cbfbbf69
FCE
2037 // NB: Since varuse_collecting_visitor also traverses down
2038 // actually called functions, we don't need to explicitly
2039 // iterate over them. Uncalled ones should have been pruned
2040 // in _opt1 above.
2041 //
2042 // for (unsigned i=0; i<s.functions.size(); i++)
2043 // s.functions[i]->body->visit (& vut);
57148ee7 2044
cbfbbf69 2045 // Now in vut.read/written, we have a mixture of all locals, globals
57148ee7
FCE
2046
2047 for (unsigned i=0; i<s.probes.size(); i++)
cbfbbf69
FCE
2048 for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
2049 {
2050 vardecl* l = s.probes[i]->locals[j];
a9e8f7e0 2051
a45664f4
JS
2052 // skip over "special" locals
2053 if (l->skip_init) { j++; continue; }
2054
cbfbbf69
FCE
2055 if (vut.read.find (l) == vut.read.end() &&
2056 vut.written.find (l) == vut.written.end())
2057 {
2203b032 2058 if (l->tok->location.file->name == s.user_file->name && // !tapset
a9e8f7e0 2059 ! s.suppress_warnings)
4af765b2 2060 s.print_warning (_F("Eliding unused variable '%s'", l->name.c_str()), l->tok);
a9e8f7e0 2061 else if (s.verbose>2)
4af765b2
LB
2062 clog << _F("Eliding unused local variable %s in %s",
2063 l->name.c_str(), s.probes[i]->name.c_str()) << endl;
c3a3c0c9
WC
2064 if (s.tapset_compile_coverage) {
2065 s.probes[i]->unused_locals.push_back
2066 (s.probes[i]->locals[j]);
2067 }
cbfbbf69
FCE
2068 s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
2069 relaxed_p = false;
2070 // don't increment j
2071 }
2072 else
27d24ae2
FCE
2073 {
2074 if (vut.written.find (l) == vut.written.end())
cfd621bc 2075 if (iterations == 0 && ! s.suppress_warnings)
6643650d
SC
2076 {
2077 stringstream o;
2078 vector<vardecl*>::iterator it;
cfd621bc
FCE
2079 for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++)
2080 if (l->name != (*it)->name)
2081 o << " " << (*it)->name;
2082 for (it = s.globals.begin(); it != s.globals.end(); it++)
2083 if (l->name != (*it)->name)
2084 o << " " << (*it)->name;
2085
4af765b2
LB
2086 s.print_warning (_F("never-assigned local variable '%s' %s",
2087 l->name.c_str(), (o.str() == "" ? "" :
2088 (_("(alternatives:") + o.str() + ")")).c_str()), l->tok);
6643650d 2089 }
27d24ae2
FCE
2090 j++;
2091 }
cbfbbf69 2092 }
57148ee7 2093
f76427a2
FCE
2094 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2095 {
2096 functiondecl *fd = it->second;
2097 for (unsigned j=0; j<fd->locals.size(); /* see below */)
2098 {
2099 vardecl* l = fd->locals[j];
2100 if (vut.read.find (l) == vut.read.end() &&
2101 vut.written.find (l) == vut.written.end())
2102 {
2203b032 2103 if (l->tok->location.file->name == s.user_file->name && // !tapset
f76427a2 2104 ! s.suppress_warnings)
4af765b2 2105 s.print_warning (_F("Eliding unused variable '%s'", l->name.c_str()), l->tok);
f76427a2 2106 else if (s.verbose>2)
4af765b2
LB
2107 clog << _F("Eliding unused local variable %s in function %s",
2108 l->name.c_str(), fd->name.c_str()) << endl;
f76427a2
FCE
2109 if (s.tapset_compile_coverage) {
2110 fd->unused_locals.push_back (fd->locals[j]);
2111 }
2112 fd->locals.erase(fd->locals.begin() + j);
2113 relaxed_p = false;
2114 // don't increment j
2115 }
2116 else
2117 {
2118 if (vut.written.find (l) == vut.written.end())
2119 if (iterations == 0 && ! s.suppress_warnings)
2120 {
2121 stringstream o;
2122 vector<vardecl*>::iterator it;
2123 for (it = fd->formal_args.begin() ;
2124 it != fd->formal_args.end(); it++)
2125 if (l->name != (*it)->name)
2126 o << " " << (*it)->name;
2127 for (it = fd->locals.begin(); it != fd->locals.end(); it++)
2128 if (l->name != (*it)->name)
2129 o << " " << (*it)->name;
2130 for (it = s.globals.begin(); it != s.globals.end(); it++)
2131 if (l->name != (*it)->name)
2132 o << " " << (*it)->name;
2133
4af765b2
LB
2134 s.print_warning (_F("never-assigned local variable '%s' %s",
2135 l->name.c_str(), (o.str() == "" ? "" :
2136 (_("(alternatives:") + o.str() + ")")).c_str()), l->tok);
f76427a2 2137 }
cfd621bc 2138
f76427a2
FCE
2139 j++;
2140 }
2141 }
2142 }
cbfbbf69
FCE
2143 for (unsigned i=0; i<s.globals.size(); /* see below */)
2144 {
2145 vardecl* l = s.globals[i];
2146 if (vut.read.find (l) == vut.read.end() &&
2147 vut.written.find (l) == vut.written.end())
2148 {
2203b032 2149 if (l->tok->location.file->name == s.user_file->name && // !tapset
a9e8f7e0 2150 ! s.suppress_warnings)
4af765b2 2151 s.print_warning (_F("Eliding unused variable '%s'", l->name.c_str()), l->tok);
a9e8f7e0 2152 else if (s.verbose>2)
4af765b2 2153 clog << _F("Eliding unused global variable %s", l->name.c_str()) << endl;
c3a3c0c9 2154 if (s.tapset_compile_coverage) {
0a102c82 2155 s.unused_globals.push_back(s.globals[i]);
c3a3c0c9 2156 }
0a102c82
SC
2157 s.globals.erase(s.globals.begin() + i);
2158 relaxed_p = false;
2159 // don't increment i
cbfbbf69
FCE
2160 }
2161 else
27d24ae2 2162 {
cfd621bc
FCE
2163 if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer
2164 if (iterations == 0 && ! s.suppress_warnings)
2165 {
2166 stringstream o;
2167 vector<vardecl*>::iterator it;
2168 for (it = s.globals.begin(); it != s.globals.end(); it++)
2169 if (l->name != (*it)->name)
2170 o << " " << (*it)->name;
57148ee7 2171
4af765b2
LB
2172 s.print_warning (_F("never assigned global variable '%s' %s", l->name.c_str(),
2173 (o.str() == "" ? "" : (_("(alternatives:") + o.str() + ")")).c_str()), l->tok);
cfd621bc
FCE
2174 }
2175
27d24ae2
FCE
2176 i++;
2177 }
cbfbbf69
FCE
2178 }
2179}
2180
2181
2182// ------------------------------------------------------------------------
2183
8bda6498 2184struct dead_assignment_remover: public update_visitor
cbfbbf69
FCE
2185{
2186 systemtap_session& session;
2187 bool& relaxed_p;
2188 const varuse_collecting_visitor& vut;
cbfbbf69
FCE
2189
2190 dead_assignment_remover(systemtap_session& s, bool& r,
57148ee7 2191 const varuse_collecting_visitor& v):
8bda6498 2192 session(s), relaxed_p(r), vut(v) {}
cbfbbf69
FCE
2193
2194 void visit_assignment (assignment* e);
f4fe2e93 2195 void visit_try_block (try_block *s);
cbfbbf69
FCE
2196};
2197
2198
cbfbbf69
FCE
2199void
2200dead_assignment_remover::visit_assignment (assignment* e)
2201{
8b095b45
JS
2202 replace (e->left);
2203 replace (e->right);
8bda6498 2204
cbfbbf69 2205 symbol* left = get_symbol_within_expression (e->left);
b0be9bdb 2206 vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target
8bda6498 2207 if (leftvar) // not unresolved $target, so intended sideeffect may be elided
cbfbbf69 2208 {
cbfbbf69
FCE
2209 if (vut.read.find(leftvar) == vut.read.end()) // var never read?
2210 {
cf9ff341
FCE
2211 // NB: Not so fast! The left side could be an array whose
2212 // index expressions may have side-effects. This would be
57148ee7 2213 // OK if we could replace the array assignment with a
cf9ff341
FCE
2214 // statement-expression containing all the index expressions
2215 // and the rvalue... but we can't.
0a102c82
SC
2216 // Another possibility is that we have an unread global variable
2217 // which are kept for probe end value display.
2218
2219 bool is_global = false;
2220 vector<vardecl*>::iterator it;
2221 for (it = session.globals.begin(); it != session.globals.end(); it++)
2222 if (leftvar->name == (*it)->name)
2223 {
2224 is_global = true;
2225 break;
2226 }
cf9ff341 2227
313db8e6 2228 varuse_collecting_visitor lvut(session);
8bda6498
JS
2229 e->left->visit (& lvut);
2230 if (lvut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars
cf9ff341 2231 {
a9e8f7e0
FCE
2232 /* PR 1119: NB: This is not necessary here. A write-only
2233 variable will also be elided soon at the next _opt2 iteration.
2234 if (e->left->tok->location.file == session.user_file->name && // !tapset
2235 ! session.suppress_warnings)
2236 clog << "WARNING: eliding write-only " << *e->left->tok << endl;
2237 else
2238 */
cf9ff341 2239 if (session.verbose>2)
4af765b2
LB
2240 clog << _F("Eliding assignment to %s at %s",
2241 leftvar->name.c_str(), lex_cast(*e->tok).c_str()) << endl;
57148ee7 2242
8bda6498 2243 provide (e->right); // goodbye assignment*
cf9ff341 2244 relaxed_p = false;
8bda6498 2245 return;
cf9ff341 2246 }
cbfbbf69
FCE
2247 }
2248 }
8bda6498 2249 provide (e);
e7625481 2250}
cbfbbf69 2251
f4fe2e93
FCE
2252
2253void
2254dead_assignment_remover::visit_try_block (try_block *s)
2255{
2256 replace (s->try_block);
2257 if (s->catch_error_var)
2258 {
2259 vardecl* errvar = s->catch_error_var->referent;
2260 if (vut.read.find(errvar) == vut.read.end()) // never read?
2261 {
2262 if (session.verbose>2)
4af765b2
LB
2263 clog << _F("Eliding unused error string catcher %s at %s",
2264 errvar->name.c_str(), lex_cast(*s->tok).c_str()) << endl;
f4fe2e93
FCE
2265 s->catch_error_var = 0;
2266 }
2267 }
2268 replace (s->catch_block);
2269 provide (s);
2270}
2271
2272
cbfbbf69
FCE
2273// Let's remove assignments to variables that are never read. We
2274// rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to
2275// be optimized away as an unused variable, and expr a candidate to be
2276// removed as a side-effect-free statement expression. Wahoo!
2277void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
2278{
2279 // Recompute the varuse data, which will probably match the opt2
2280 // copy of the computation, except for those totally unused
2281 // variables that opt2 removed.
313db8e6 2282 varuse_collecting_visitor vut(s);
cbfbbf69
FCE
2283 for (unsigned i=0; i<s.probes.size(); i++)
2284 s.probes[i]->body->visit (& vut); // includes reachable functions too
2285
2286 dead_assignment_remover dar (s, relaxed_p, vut);
2287 // This instance may be reused for multiple probe/function body trims.
2288
2289 for (unsigned i=0; i<s.probes.size(); i++)
8b095b45 2290 dar.replace (s.probes[i]->body);
8bda6498
JS
2291 for (map<string,functiondecl*>::iterator it = s.functions.begin();
2292 it != s.functions.end(); it++)
8b095b45 2293 dar.replace (it->second->body);
cbfbbf69 2294 // The rewrite operation is performed within the visitor.
27d24ae2
FCE
2295
2296 // XXX: we could also zap write-only globals here
cbfbbf69
FCE
2297}
2298
2299
2300// ------------------------------------------------------------------------
2301
1cd151d5 2302struct dead_stmtexpr_remover: public update_visitor
cbfbbf69
FCE
2303{
2304 systemtap_session& session;
2305 bool& relaxed_p;
1b07c728 2306 set<vardecl*> focal_vars; // vars considered subject to side-effects
cbfbbf69 2307
57148ee7 2308 dead_stmtexpr_remover(systemtap_session& s, bool& r):
1cd151d5 2309 session(s), relaxed_p(r) {}
cbfbbf69
FCE
2310
2311 void visit_block (block *s);
f4fe2e93 2312 void visit_try_block (try_block *s);
ba6f838d 2313 void visit_null_statement (null_statement *s);
739a3e81
FCE
2314 void visit_if_statement (if_statement* s);
2315 void visit_foreach_loop (foreach_loop *s);
2316 void visit_for_loop (for_loop *s);
cbfbbf69
FCE
2317 // XXX: and other places where stmt_expr's might be nested
2318
2319 void visit_expr_statement (expr_statement *s);
2320};
2321
2322
ba6f838d
FCE
2323void
2324dead_stmtexpr_remover::visit_null_statement (null_statement *s)
2325{
2326 // easy!
2327 if (session.verbose>2)
4af765b2 2328 clog << _("Eliding side-effect-free null statement ") << *s->tok << endl;
1cd151d5
JS
2329 s = 0;
2330 provide (s);
ba6f838d
FCE
2331}
2332
2333
cbfbbf69
FCE
2334void
2335dead_stmtexpr_remover::visit_block (block *s)
2336{
ba6f838d
FCE
2337 vector<statement*> new_stmts;
2338 for (unsigned i=0; i<s->statements.size(); i++ )
cbfbbf69 2339 {
1cd151d5
JS
2340 statement* new_stmt = require (s->statements[i], true);
2341 if (new_stmt != 0)
bea72737
JS
2342 {
2343 // flatten nested blocks into this one
1cd151d5 2344 block *b = dynamic_cast<block *>(new_stmt);
bea72737
JS
2345 if (b)
2346 {
2347 if (session.verbose>2)
4af765b2 2348 clog << _("Flattening nested block ") << *b->tok << endl;
bea72737
JS
2349 new_stmts.insert(new_stmts.end(),
2350 b->statements.begin(), b->statements.end());
2351 relaxed_p = false;
2352 }
2353 else
1cd151d5 2354 new_stmts.push_back (new_stmt);
bea72737 2355 }
cbfbbf69 2356 }
ba6f838d
FCE
2357 if (new_stmts.size() == 0)
2358 {
2359 if (session.verbose>2)
4af765b2 2360 clog << _("Eliding side-effect-free empty block ") << *s->tok << endl;
1cd151d5 2361 s = 0;
ba6f838d
FCE
2362 }
2363 else if (new_stmts.size() == 1)
2364 {
2365 if (session.verbose>2)
4af765b2 2366 clog << _("Eliding side-effect-free singleton block ") << *s->tok << endl;
1cd151d5
JS
2367 provide (new_stmts[0]);
2368 return;
ba6f838d
FCE
2369 }
2370 else
1cd151d5
JS
2371 s->statements = new_stmts;
2372 provide (s);
cbfbbf69
FCE
2373}
2374
f4fe2e93
FCE
2375
2376void
2377dead_stmtexpr_remover::visit_try_block (try_block *s)
2378{
2379 replace (s->try_block, true);
2380 replace (s->catch_block, true); // null catch{} is ok and useful
2381 if (s->try_block == 0)
2382 {
2383 if (session.verbose>2)
4af765b2 2384 clog << _("Eliding empty try {} block ") << *s->tok << endl;
f4fe2e93
FCE
2385 s = 0;
2386 }
2387 provide (s);
2388}
2389
2390
739a3e81
FCE
2391void
2392dead_stmtexpr_remover::visit_if_statement (if_statement *s)
2393{
8b095b45
JS
2394 replace (s->thenblock, true);
2395 replace (s->elseblock, true);
ba6f838d 2396
bea72737 2397 if (s->thenblock == 0)
ba6f838d 2398 {
bea72737
JS
2399 if (s->elseblock == 0)
2400 {
2401 // We may be able to elide this statement, if the condition
2402 // expression is side-effect-free.
313db8e6 2403 varuse_collecting_visitor vct(session);
bea72737
JS
2404 s->condition->visit(& vct);
2405 if (vct.side_effect_free ())
2406 {
2407 if (session.verbose>2)
4af765b2 2408 clog << _("Eliding side-effect-free if statement ")
bea72737 2409 << *s->tok << endl;
1cd151d5 2410 s = 0; // yeah, baby
bea72737
JS
2411 }
2412 else
2413 {
2414 // We can still turn it into a simple expr_statement though...
2415 if (session.verbose>2)
4af765b2 2416 clog << _("Creating simple evaluation from if statement ")
bea72737
JS
2417 << *s->tok << endl;
2418 expr_statement *es = new expr_statement;
2419 es->value = s->condition;
2420 es->tok = es->value->tok;
1cd151d5
JS
2421 provide (es);
2422 return;
bea72737
JS
2423 }
2424 }
2425 else
ba6f838d 2426 {
bea72737
JS
2427 // For an else without a then, we can invert the condition logic to
2428 // avoid having a null statement in the thenblock
ba6f838d 2429 if (session.verbose>2)
4af765b2 2430 clog << _("Inverting the condition of if statement ")
bea72737
JS
2431 << *s->tok << endl;
2432 unary_expression *ue = new unary_expression;
2433 ue->operand = s->condition;
2434 ue->tok = ue->operand->tok;
2435 ue->op = "!";
2436 s->condition = ue;
2437 s->thenblock = s->elseblock;
2438 s->elseblock = 0;
ba6f838d
FCE
2439 }
2440 }
1cd151d5 2441 provide (s);
739a3e81
FCE
2442}
2443
2444void
2445dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
2446{
8b095b45 2447 replace (s->block, true);
ba6f838d
FCE
2448
2449 if (s->block == 0)
2450 {
10328bcf 2451 // XXX what if s->limit has side effects?
c261711d 2452 // XXX what about s->indexes or s->value used outside the loop?
ba6f838d 2453 if (session.verbose>2)
4af765b2 2454 clog << _("Eliding side-effect-free foreach statement ") << *s->tok << endl;
1cd151d5 2455 s = 0; // yeah, baby
ba6f838d 2456 }
1cd151d5 2457 provide (s);
739a3e81
FCE
2458}
2459
2460void
2461dead_stmtexpr_remover::visit_for_loop (for_loop *s)
2462{
8b095b45 2463 replace (s->block, true);
ba6f838d
FCE
2464
2465 if (s->block == 0)
2466 {
2467 // We may be able to elide this statement, if the condition
2468 // expression is side-effect-free.
313db8e6 2469 varuse_collecting_visitor vct(session);
ba6f838d
FCE
2470 if (s->init) s->init->visit(& vct);
2471 s->cond->visit(& vct);
2472 if (s->incr) s->incr->visit(& vct);
2473 if (vct.side_effect_free ())
2474 {
2475 if (session.verbose>2)
4af765b2 2476 clog << _("Eliding side-effect-free for statement ") << *s->tok << endl;
1cd151d5
JS
2477 s = 0; // yeah, baby
2478 }
2479 else
2480 {
2481 // Can't elide this whole statement; put a null in there.
f946b10f 2482 s->block = new null_statement(s->tok);
ba6f838d 2483 }
ba6f838d 2484 }
1cd151d5 2485 provide (s);
739a3e81
FCE
2486}
2487
2488
cbfbbf69
FCE
2489
2490void
2491dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
2492{
2493 // Run a varuse query against the operand expression. If it has no
2494 // side-effects, replace the entire statement expression by a null
1cd151d5 2495 // statement with the provide() call.
cbfbbf69
FCE
2496 //
2497 // Unlike many other visitors, we do *not* traverse this outermost
2498 // one into the expression subtrees. There is no need - no
2499 // expr_statement nodes will be found there. (Function bodies
2500 // need to be visited explicitly by our caller.)
2501 //
2502 // NB. While we don't share nodes in the parse tree, let's not
2503 // deallocate *s anyway, just in case...
2504
313db8e6 2505 varuse_collecting_visitor vut(session);
cbfbbf69 2506 s->value->visit (& vut);
57148ee7 2507
1cd151d5 2508 if (vut.side_effect_free_wrt (focal_vars))
cbfbbf69 2509 {
a9e8f7e0
FCE
2510 /* PR 1119: NB: this message is not a good idea here. It can
2511 name some arbitrary RHS expression of an assignment.
2512 if (s->value->tok->location.file == session.user_file->name && // not tapset
2513 ! session.suppress_warnings)
b43003da 2514 clog << "WARNING: eliding never-assigned " << *s->value->tok << endl;
57148ee7 2515 else
a9e8f7e0 2516 */
b0ee93c4 2517 if (session.verbose>2)
4af765b2 2518 clog << _("Eliding side-effect-free expression ")
cbfbbf69
FCE
2519 << *s->tok << endl;
2520
ba6f838d
FCE
2521 // NB: this 0 pointer is invalid to leave around for any length of
2522 // time, but the parent parse tree objects above handle it.
1cd151d5 2523 s = 0;
cbfbbf69
FCE
2524 relaxed_p = false;
2525 }
1cd151d5 2526 provide (s);
cbfbbf69
FCE
2527}
2528
2529
2530void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
2531{
2532 // Finally, let's remove some statement-expressions that have no
2533 // side-effect. These should be exactly those whose private varuse
2534 // visitors come back with an empty "written" and "embedded" lists.
57148ee7 2535
cbfbbf69
FCE
2536 dead_stmtexpr_remover duv (s, relaxed_p);
2537 // This instance may be reused for multiple probe/function body trims.
2538
2539 for (unsigned i=0; i<s.probes.size(); i++)
1b07c728 2540 {
85007c04 2541 if (pending_interrupts) break;
f76427a2 2542
ba6f838d
FCE
2543 derived_probe* p = s.probes[i];
2544
1b07c728
FCE
2545 duv.focal_vars.clear ();
2546 duv.focal_vars.insert (s.globals.begin(),
2547 s.globals.end());
ba6f838d
FCE
2548 duv.focal_vars.insert (p->locals.begin(),
2549 p->locals.end());
2550
8b095b45 2551 duv.replace (p->body, true);
ba6f838d
FCE
2552 if (p->body == 0)
2553 {
7175b492
FCE
2554 if (! s.suppress_warnings
2555 && ! s.timing) // PR10070
4af765b2 2556 s.print_warning (_F("side-effect-free probe '%s'", p->name.c_str()), p->tok);
ba6f838d 2557
f946b10f 2558 p->body = new null_statement(p->tok);
27d24ae2
FCE
2559
2560 // XXX: possible duplicate warnings; see below
ba6f838d 2561 }
1b07c728 2562 }
f76427a2 2563 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
1b07c728 2564 {
85007c04 2565 if (pending_interrupts) break;
f76427a2
FCE
2566
2567 functiondecl* fn = it->second;
1b07c728 2568 duv.focal_vars.clear ();
ba6f838d
FCE
2569 duv.focal_vars.insert (fn->locals.begin(),
2570 fn->locals.end());
2571 duv.focal_vars.insert (fn->formal_args.begin(),
2572 fn->formal_args.end());
1b07c728
FCE
2573 duv.focal_vars.insert (s.globals.begin(),
2574 s.globals.end());
ba6f838d 2575
8b095b45 2576 duv.replace (fn->body, true);
ba6f838d
FCE
2577 if (fn->body == 0)
2578 {
2579 if (! s.suppress_warnings)
4af765b2 2580 s.print_warning (_F("side-effect-free function '%s'", fn->name.c_str()), fn->tok);
ba6f838d 2581
f946b10f 2582 fn->body = new null_statement(fn->tok);
27d24ae2
FCE
2583
2584 // XXX: the next iteration of the outer optimization loop may
2585 // take this new null_statement away again, and thus give us a
2586 // fresh warning. It would be better if this fixup was performed
2587 // only after the relaxation iterations.
2588 // XXX: or else see bug #6469.
ba6f838d 2589 }
1b07c728 2590 }
cbfbbf69
FCE
2591}
2592
bea72737
JS
2593
2594// ------------------------------------------------------------------------
2595
2596// The goal of this visitor is to reduce top-level expressions in void context
2597// into separate statements that evaluate each subcomponent of the expression.
2598// The dead-statement-remover can later remove some parts if they have no side
2599// effects.
9f9873df
JS
2600//
2601// All expressions must be overridden here so we never visit their subexpressions
2602// accidentally. Thus, the only visited expressions should be value of an
2603// expr_statement.
2604//
2605// For an expression to replace its expr_statement with something else, it will
2606// let the new statement provide(), and then provide(0) for itself. The
2607// expr_statement will take this as a sign that it's been replaced.
2608struct void_statement_reducer: public update_visitor
bea72737
JS
2609{
2610 systemtap_session& session;
2611 bool& relaxed_p;
bea72737
JS
2612 set<vardecl*> focal_vars; // vars considered subject to side-effects
2613
2614 void_statement_reducer(systemtap_session& s, bool& r):
9f9873df 2615 session(s), relaxed_p(r) {}
bea72737 2616
133c7b1d 2617 void visit_expr_statement (expr_statement* s);
9f9873df
JS
2618
2619 // expressions in conditional / loop controls are definitely a side effect,
2620 // but still recurse into the child statements
bea72737
JS
2621 void visit_if_statement (if_statement* s);
2622 void visit_for_loop (for_loop* s);
2623 void visit_foreach_loop (foreach_loop* s);
2624
2625 // these expressions get rewritten into their statement equivalents
2626 void visit_logical_or_expr (logical_or_expr* e);
2627 void visit_logical_and_expr (logical_and_expr* e);
2628 void visit_ternary_expression (ternary_expression* e);
2629
2630 // all of these can be reduced into simpler statements
2631 void visit_binary_expression (binary_expression* e);
2632 void visit_unary_expression (unary_expression* e);
2633 void visit_comparison (comparison* e);
2634 void visit_concatenation (concatenation* e);
2635 void visit_functioncall (functioncall* e);
2636 void visit_print_format (print_format* e);
6fda2dff 2637 void visit_target_symbol (target_symbol* e);
9b5af295 2638 void visit_cast_op (cast_op* e);
30263a73 2639 void visit_defined_op (defined_op* e);
bea72737
JS
2640
2641 // these are a bit hairy to grok due to the intricacies of indexables and
2642 // stats, so I'm chickening out and skipping them...
9f9873df
JS
2643 void visit_array_in (array_in* e) { provide (e); }
2644 void visit_arrayindex (arrayindex* e) { provide (e); }
2645 void visit_stat_op (stat_op* e) { provide (e); }
2646 void visit_hist_op (hist_op* e) { provide (e); }
bea72737
JS
2647
2648 // these can't be reduced because they always have an effect
9f9873df
JS
2649 void visit_return_statement (return_statement* s) { provide (s); }
2650 void visit_delete_statement (delete_statement* s) { provide (s); }
2651 void visit_pre_crement (pre_crement* e) { provide (e); }
2652 void visit_post_crement (post_crement* e) { provide (e); }
2653 void visit_assignment (assignment* e) { provide (e); }
bea72737
JS
2654};
2655
2656
133c7b1d
JS
2657void
2658void_statement_reducer::visit_expr_statement (expr_statement* s)
2659{
8b095b45 2660 replace (s->value, true);
133c7b1d 2661
9f9873df
JS
2662 // if the expression provides 0, that's our signal that a new
2663 // statement has been provided, so we shouldn't provide this one.
2664 if (s->value != 0)
2665 provide(s);
bea72737
JS
2666}
2667
2668void
2669void_statement_reducer::visit_if_statement (if_statement* s)
2670{
9f9873df 2671 // s->condition is never void
8b095b45
JS
2672 replace (s->thenblock);
2673 replace (s->elseblock);
9f9873df 2674 provide (s);
bea72737
JS
2675}
2676
2677void
2678void_statement_reducer::visit_for_loop (for_loop* s)
2679{
9f9873df 2680 // s->init/cond/incr are never void
8b095b45 2681 replace (s->block);
9f9873df 2682 provide (s);
bea72737
JS
2683}
2684
2685void
2686void_statement_reducer::visit_foreach_loop (foreach_loop* s)
2687{
c261711d 2688 // s->indexes/base/value/limit are never void
8b095b45 2689 replace (s->block);
9f9873df 2690 provide (s);
bea72737
JS
2691}
2692
2693void
2694void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
2695{
2696 // In void context, the evaluation of "a || b" is exactly like
2697 // "if (!a) b", so let's do that instead.
2698
bea72737 2699 if (session.verbose>2)
4af765b2 2700 clog << _("Creating if statement from unused logical-or ")
bea72737
JS
2701 << *e->tok << endl;
2702
2703 if_statement *is = new if_statement;
2704 is->tok = e->tok;
2705 is->elseblock = 0;
bea72737
JS
2706
2707 unary_expression *ue = new unary_expression;
2708 ue->operand = e->left;
2709 ue->tok = e->tok;
2710 ue->op = "!";
2711 is->condition = ue;
2712
133c7b1d 2713 expr_statement *es = new expr_statement;
bea72737
JS
2714 es->value = e->right;
2715 es->tok = es->value->tok;
2716 is->thenblock = es;
2717
2718 is->visit(this);
2719 relaxed_p = false;
9f9873df
JS
2720 e = 0;
2721 provide (e);
bea72737
JS
2722}
2723
2724void
2725void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
2726{
2727 // In void context, the evaluation of "a && b" is exactly like
2728 // "if (a) b", so let's do that instead.
2729
bea72737 2730 if (session.verbose>2)
4af765b2 2731 clog << _("Creating if statement from unused logical-and ")
bea72737
JS
2732 << *e->tok << endl;
2733
2734 if_statement *is = new if_statement;
2735 is->tok = e->tok;
2736 is->elseblock = 0;
2737 is->condition = e->left;
bea72737 2738
133c7b1d 2739 expr_statement *es = new expr_statement;
bea72737
JS
2740 es->value = e->right;
2741 es->tok = es->value->tok;
2742 is->thenblock = es;
2743
2744 is->visit(this);
2745 relaxed_p = false;
9f9873df
JS
2746 e = 0;
2747 provide (e);
bea72737
JS
2748}
2749
2750void
2751void_statement_reducer::visit_ternary_expression (ternary_expression* e)
2752{
2753 // In void context, the evaluation of "a ? b : c" is exactly like
2754 // "if (a) b else c", so let's do that instead.
2755
bea72737 2756 if (session.verbose>2)
4af765b2 2757 clog << _("Creating if statement from unused ternary expression ")
bea72737
JS
2758 << *e->tok << endl;
2759
2760 if_statement *is = new if_statement;
2761 is->tok = e->tok;
2762 is->condition = e->cond;
bea72737 2763
133c7b1d 2764 expr_statement *es = new expr_statement;
bea72737
JS
2765 es->value = e->truevalue;
2766 es->tok = es->value->tok;
2767 is->thenblock = es;
2768
2769 es = new expr_statement;
2770 es->value = e->falsevalue;
2771 es->tok = es->value->tok;
2772 is->elseblock = es;
2773
2774 is->visit(this);
2775 relaxed_p = false;
9f9873df
JS
2776 e = 0;
2777 provide (e);
bea72737
JS
2778}
2779
2780void
2781void_statement_reducer::visit_binary_expression (binary_expression* e)
2782{
2783 // When the result of a binary operation isn't needed, it's just as good to
2784 // evaluate the operands as sequential statements in a block.
2785
bea72737 2786 if (session.verbose>2)
4af765b2 2787 clog << _("Eliding unused binary ") << *e->tok << endl;
bea72737
JS
2788
2789 block *b = new block;
9f9873df 2790 b->tok = e->tok;
bea72737 2791
133c7b1d 2792 expr_statement *es = new expr_statement;
bea72737
JS
2793 es->value = e->left;
2794 es->tok = es->value->tok;
2795 b->statements.push_back(es);
2796
2797 es = new expr_statement;
2798 es->value = e->right;
2799 es->tok = es->value->tok;
2800 b->statements.push_back(es);
2801
2802 b->visit(this);
2803 relaxed_p = false;
9f9873df
JS
2804 e = 0;
2805 provide (e);
bea72737
JS
2806}
2807
2808void
2809void_statement_reducer::visit_unary_expression (unary_expression* e)
2810{
2811 // When the result of a unary operation isn't needed, it's just as good to
2812 // evaluate the operand directly
2813
bea72737 2814 if (session.verbose>2)
4af765b2 2815 clog << _("Eliding unused unary ") << *e->tok << endl;
bea72737 2816
bea72737 2817 relaxed_p = false;
9f9873df 2818 e->operand->visit(this);
bea72737
JS
2819}
2820
2821void
2822void_statement_reducer::visit_comparison (comparison* e)
2823{
2824 visit_binary_expression(e);
2825}
2826
2827void
2828void_statement_reducer::visit_concatenation (concatenation* e)
2829{
2830 visit_binary_expression(e);
2831}
2832
2833void
2834void_statement_reducer::visit_functioncall (functioncall* e)
2835{
2836 // If a function call is pure and its result ignored, we can elide the call
c7d47935 2837 // and just evaluate the arguments in sequence
bea72737
JS
2838
2839 if (!e->args.size())
9f9873df
JS
2840 {
2841 provide (e);
2842 return;
2843 }
bea72737 2844
313db8e6 2845 varuse_collecting_visitor vut(session);
bea72737
JS
2846 vut.traversed.insert (e->referent);
2847 vut.current_function = e->referent;
2848 e->referent->body->visit (& vut);
2849 if (!vut.side_effect_free_wrt (focal_vars))
9f9873df
JS
2850 {
2851 provide (e);
2852 return;
2853 }
bea72737
JS
2854
2855 if (session.verbose>2)
4af765b2 2856 clog << _("Eliding side-effect-free function call ") << *e->tok << endl;
bea72737 2857
133c7b1d
JS
2858 block *b = new block;
2859 b->tok = e->tok;
bea72737 2860
133c7b1d 2861 for (unsigned i=0; i<e->args.size(); i++ )
bea72737 2862 {
133c7b1d
JS
2863 expr_statement *es = new expr_statement;
2864 es->value = e->args[i];
2865 es->tok = es->value->tok;
bea72737 2866 b->statements.push_back(es);
bea72737
JS
2867 }
2868
133c7b1d 2869 b->visit(this);
bea72737 2870 relaxed_p = false;
9f9873df
JS
2871 e = 0;
2872 provide (e);
bea72737
JS
2873}
2874
2875void
2876void_statement_reducer::visit_print_format (print_format* e)
2877{
2878 // When an sprint's return value is ignored, we can simply evaluate the
2879 // arguments in sequence
2880
2881 if (e->print_to_stream || !e->args.size())
9f9873df
JS
2882 {
2883 provide (e);
2884 return;
2885 }
bea72737
JS
2886
2887 if (session.verbose>2)
4af765b2 2888 clog << _("Eliding unused print ") << *e->tok << endl;
bea72737 2889
133c7b1d
JS
2890 block *b = new block;
2891 b->tok = e->tok;
bea72737 2892
133c7b1d 2893 for (unsigned i=0; i<e->args.size(); i++ )
bea72737 2894 {
133c7b1d
JS
2895 expr_statement *es = new expr_statement;
2896 es->value = e->args[i];
2897 es->tok = es->value->tok;
bea72737 2898 b->statements.push_back(es);
bea72737
JS
2899 }
2900
133c7b1d 2901 b->visit(this);
bea72737 2902 relaxed_p = false;
9f9873df
JS
2903 e = 0;
2904 provide (e);
bea72737
JS
2905}
2906
6fda2dff
JS
2907void
2908void_statement_reducer::visit_target_symbol (target_symbol* e)
2909{
2910 // When target_symbol isn't needed, it's just as good to
2911 // evaluate any array indexes directly
2912
2913 block *b = new block;
2914 b->tok = e->tok;
2915
2916 for (unsigned i=0; i<e->components.size(); i++ )
2917 {
2918 if (e->components[i].type != target_symbol::comp_expression_array_index)
2919 continue;
2920
2921 expr_statement *es = new expr_statement;
2922 es->value = e->components[i].expr_index;
2923 es->tok = es->value->tok;
2924 b->statements.push_back(es);
2925 }
2926
2927 if (b->statements.empty())
2928 {
2929 delete b;
2930 provide (e);
2931 return;
2932 }
2933
2934 if (session.verbose>2)
4af765b2 2935 clog << _("Eliding unused target symbol ") << *e->tok << endl;
6fda2dff
JS
2936
2937 b->visit(this);
2938 relaxed_p = false;
2939 e = 0;
2940 provide (e);
2941}
2942
9b5af295
JS
2943void
2944void_statement_reducer::visit_cast_op (cast_op* e)
2945{
2946 // When the result of a cast operation isn't needed, it's just as good to
6fda2dff
JS
2947 // evaluate the operand and any array indexes directly
2948
2949 block *b = new block;
2950 b->tok = e->tok;
2951
2952 expr_statement *es = new expr_statement;
2953 es->value = e->operand;
2954 es->tok = es->value->tok;
2955 b->statements.push_back(es);
2956
2957 for (unsigned i=0; i<e->components.size(); i++ )
2958 {
2959 if (e->components[i].type != target_symbol::comp_expression_array_index)
2960 continue;
2961
2962 es = new expr_statement;
2963 es->value = e->components[i].expr_index;
2964 es->tok = es->value->tok;
2965 b->statements.push_back(es);
2966 }
9b5af295
JS
2967
2968 if (session.verbose>2)
4af765b2 2969 clog << _("Eliding unused typecast ") << *e->tok << endl;
9b5af295 2970
6fda2dff 2971 b->visit(this);
9b5af295 2972 relaxed_p = false;
6fda2dff
JS
2973 e = 0;
2974 provide (e);
9b5af295
JS
2975}
2976
bea72737 2977
30263a73
FCE
2978void
2979void_statement_reducer::visit_defined_op (defined_op* e)
2980{
2981 // When the result of a @defined operation isn't needed, just elide
2982 // it entirely. Its operand $expression must already be
2983 // side-effect-free.
2984
2985 if (session.verbose>2)
4af765b2 2986 clog << _("Eliding unused check ") << *e->tok << endl;
30263a73
FCE
2987
2988 relaxed_p = false;
2989 e = 0;
2990 provide (e);
2991}
2992
2993
2994
bea72737
JS
2995void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
2996{
2997 // Let's simplify statements with unused computed values.
2998
2999 void_statement_reducer vuv (s, relaxed_p);
3000 // This instance may be reused for multiple probe/function body trims.
3001
3002 vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
3003
3004 for (unsigned i=0; i<s.probes.size(); i++)
8b095b45 3005 vuv.replace (s.probes[i]->body);
9f9873df
JS
3006 for (map<string,functiondecl*>::iterator it = s.functions.begin();
3007 it != s.functions.end(); it++)
8b095b45 3008 vuv.replace (it->second->body);
bea72737
JS
3009}
3010
3011
10328bcf
JS
3012struct const_folder: public update_visitor
3013{
3014 systemtap_session& session;
3015 bool& relaxed_p;
3016
3017 const_folder(systemtap_session& s, bool& r):
3018 session(s), relaxed_p(r), last_number(0), last_string(0) {}
3019
3020 literal_number* last_number;
3021 literal_number* get_number(expression*& e);
3022 void visit_literal_number (literal_number* e);
3023
3024 literal_string* last_string;
3025 literal_string* get_string(expression*& e);
3026 void visit_literal_string (literal_string* e);
3027
f4869658
JS
3028 void get_literal(expression*& e, literal_number*& n, literal_string*& s);
3029
10328bcf
JS
3030 void visit_if_statement (if_statement* s);
3031 void visit_for_loop (for_loop* s);
3032 void visit_foreach_loop (foreach_loop* s);
3033 void visit_binary_expression (binary_expression* e);
3034 void visit_unary_expression (unary_expression* e);
3035 void visit_logical_or_expr (logical_or_expr* e);
3036 void visit_logical_and_expr (logical_and_expr* e);
3037 void visit_comparison (comparison* e);
3038 void visit_concatenation (concatenation* e);
3039 void visit_ternary_expression (ternary_expression* e);
b7aedf26 3040 void visit_defined_op (defined_op* e);
9fab2262 3041 void visit_target_symbol (target_symbol* e);
10328bcf
JS
3042};
3043
f4869658
JS
3044void
3045const_folder::get_literal(expression*& e,
3046 literal_number*& n,
3047 literal_string*& s)
3048{
3049 replace (e);
3050 n = (e == last_number) ? last_number : NULL;
3051 s = (e == last_string) ? last_string : NULL;
3052}
3053
10328bcf
JS
3054literal_number*
3055const_folder::get_number(expression*& e)
3056{
3057 replace (e);
3058 return (e == last_number) ? last_number : NULL;
3059}
3060
3061void
3062const_folder::visit_literal_number (literal_number* e)
3063{
3064 last_number = e;
3065 provide (e);
3066}
3067
3068literal_string*
3069const_folder::get_string(expression*& e)
3070{
3071 replace (e);
3072 return (e == last_string) ? last_string : NULL;
3073}
3074
3075void
3076const_folder::visit_literal_string (literal_string* e)
3077{
3078 last_string = e;
3079 provide (e);
3080}
3081
3082void
3083const_folder::visit_if_statement (if_statement* s)
3084{
3085 literal_number* cond = get_number (s->condition);
3086 if (!cond)
3087 {
3088 replace (s->thenblock);
3089 replace (s->elseblock);
3090 provide (s);
3091 }
3092 else
3093 {
3094 if (session.verbose>2)
4af765b2
LB
3095 clog << _F("Collapsing constant-%" PRIi64 " if-statement %s",
3096 cond->value, lex_cast(*s->tok).c_str()) << endl;
10328bcf
JS
3097 relaxed_p = false;
3098
3099 statement* n = cond->value ? s->thenblock : s->elseblock;
3100 if (n)
3101 n->visit (this);
3102 else
3103 provide (new null_statement (s->tok));
3104 }
3105}
3106
3107void
3108const_folder::visit_for_loop (for_loop* s)
3109{
3110 literal_number* cond = get_number (s->cond);
3111 if (!cond || cond->value)
3112 {
3113 replace (s->init);
3114 replace (s->incr);
3115 replace (s->block);
3116 provide (s);
3117 }
3118 else
3119 {
3120 if (session.verbose>2)
4af765b2 3121 clog << _("Collapsing constantly-false for-loop ") << *s->tok << endl;
10328bcf
JS
3122 relaxed_p = false;
3123
3124 if (s->init)
3125 s->init->visit (this);
3126 else
3127 provide (new null_statement (s->tok));
3128 }
3129}
3130
3131void
3132const_folder::visit_foreach_loop (foreach_loop* s)
3133{
3134 literal_number* limit = get_number (s->limit);
3135 if (!limit || limit->value > 0)
3136 {
3137 for (unsigned i = 0; i < s->indexes.size(); ++i)
3138 replace (s->indexes[i]);
3139 replace (s->base);
c261711d 3140 replace (s->value);
10328bcf
JS
3141 replace (s->block);
3142 provide (s);
3143 }
3144 else
3145 {
3146 if (session.verbose>2)
4af765b2 3147 clog << _("Collapsing constantly-limited foreach-loop ") << *s->tok << endl;
10328bcf
JS
3148 relaxed_p = false;
3149
3150 provide (new null_statement (s->tok));
3151 }
3152}
3153
3154void
3155const_folder::visit_binary_expression (binary_expression* e)
3156{
e7227e90
JS
3157 int64_t value;
3158 literal_number* left = get_number (e->left);
3159 literal_number* right = get_number (e->right);
3160
3161 if (right && !right->value && (e->op == "/" || e->op == "%"))
3162 {
3163 // Give divide-by-zero a chance to be optimized out elsewhere,
3164 // and if not it will be a runtime error anyway...
3165 provide (e);
3166 return;
3167 }
3168
3169 if (left && right)
3170 {
3171 if (e->op == "+")
3172 value = left->value + right->value;
3173 else if (e->op == "-")
3174 value = left->value - right->value;
3175 else if (e->op == "*")
3176 value = left->value * right->value;
3177 else if (e->op == "&")
3178 value = left->value & right->value;
3179 else if (e->op == "|")
3180 value = left->value | right->value;
3181 else if (e->op == "^")
3182 value = left->value ^ right->value;
3183 else if (e->op == ">>")
3184 value = left->value >> max(min(right->value, (int64_t)64), (int64_t)0);
3185 else if (e->op == "<<")
3186 value = left->value << max(min(right->value, (int64_t)64), (int64_t)0);
3187 else if (e->op == "/")
3188 value = (left->value == LLONG_MIN && right->value == -1) ? LLONG_MIN :
3189 left->value / right->value;
3190 else if (e->op == "%")
3191 value = (left->value == LLONG_MIN && right->value == -1) ? 0 :
3192 left->value % right->value;
3193 else
4af765b2 3194 throw semantic_error (_("unsupported binary operator ") + e->op);
e7227e90
JS
3195 }
3196
3197 else if ((left && ((left->value == 0 && (e->op == "*" || e->op == "&" ||
3198 e->op == ">>" || e->op == "<<" )) ||
3199 (left->value ==-1 && (e->op == "|" || e->op == ">>"))))
3200 ||
3201 (right && ((right->value == 0 && (e->op == "*" || e->op == "&")) ||
3202 (right->value == 1 && (e->op == "%")) ||
3203 (right->value ==-1 && (e->op == "%" || e->op == "|")))))
3204 {
3205 expression* other = left ? e->right : e->left;
3206 varuse_collecting_visitor vu(session);
3207 other->visit(&vu);
3208 if (!vu.side_effect_free())
3209 {
3210 provide (e);
3211 return;
3212 }
3213
3214 if (left)
3215 value = left->value;
3216 else if (e->op == "%")
3217 value = 0;
3218 else
3219 value = right->value;
3220 }
3221
3222 else if ((left && ((left->value == 0 && (e->op == "+" || e->op == "|" ||
3223 e->op == "^")) ||
3224 (left->value == 1 && (e->op == "*")) ||
3225 (left->value ==-1 && (e->op == "&"))))
3226 ||
3227 (right && ((right->value == 0 && (e->op == "+" || e->op == "-" ||
3228 e->op == "|" || e->op == "^")) ||
3229 (right->value == 1 && (e->op == "*" || e->op == "/")) ||
3230 (right->value ==-1 && (e->op == "&")) ||
3231 (right->value <= 0 && (e->op == ">>" || e->op == "<<")))))
3232 {
3233 if (session.verbose>2)
4af765b2 3234 clog << _("Collapsing constant-identity binary operator ") << *e->tok << endl;
e7227e90
JS
3235 relaxed_p = false;
3236
3237 provide (left ? e->right : e->left);
3238 return;
3239 }
3240
3241 else
3242 {
3243 provide (e);
3244 return;
3245 }
3246
3247 if (session.verbose>2)
4af765b2
LB
3248 clog << _F("Collapsing constant-%" PRIi64 " binary operator %s",
3249 value, lex_cast(*e->tok).c_str()) << endl;
e7227e90
JS
3250 relaxed_p = false;
3251
3252 literal_number* n = new literal_number(value);
3253 n->tok = e->tok;
3254 n->visit (this);
10328bcf
JS
3255}
3256
3257void
3258const_folder::visit_unary_expression (unary_expression* e)
3259{
3260 literal_number* operand = get_number (e->operand);
3261 if (!operand)
3262 provide (e);
3263 else
3264 {
3265 if (session.verbose>2)
4af765b2 3266 clog << _("Collapsing constant unary ") << *e->tok << endl;
10328bcf
JS
3267 relaxed_p = false;
3268
3269 literal_number* n = new literal_number (*operand);
3270 n->tok = e->tok;
3271 if (e->op == "+")
3272 ; // nothing to do
3273 else if (e->op == "-")
3274 n->value = -n->value;
3275 else if (e->op == "!")
3276 n->value = !n->value;
3277 else if (e->op == "~")
3278 n->value = ~n->value;
3279 else
4af765b2 3280 throw semantic_error (_("unsupported unary operator ") + e->op);
10328bcf
JS
3281 n->visit (this);
3282 }
3283}
3284
3285void
3286const_folder::visit_logical_or_expr (logical_or_expr* e)
3287{
a7e58d4c
JS
3288 int64_t value;
3289 literal_number* left = get_number (e->left);
3290 literal_number* right = get_number (e->right);
3291
3292 if (left && right)
3293 value = left->value || right->value;
3294
3295 else if ((left && left->value) || (right && right->value))
3296 {
3297 // If the const is on the left, we get to short-circuit the right
3298 // immediately. Otherwise, we can only eliminate the LHS if it's pure.
3299 if (right)
3300 {
3301 varuse_collecting_visitor vu(session);
3302 e->left->visit(&vu);
3303 if (!vu.side_effect_free())
3304 {
3305 provide (e);
3306 return;
3307 }
3308 }
3309
3310 value = 1;
3311 }
3312
3313 // We might also get rid of useless "0||x" and "x||0", except it does
3314 // normalize x to 0 or 1. We could change it to "!!x", but it's not clear
3315 // that this would gain us much.
3316
3317 else
3318 {
3319 provide (e);
3320 return;
3321 }
3322
3323 if (session.verbose>2)
4af765b2 3324 clog << _("Collapsing constant logical-OR ") << *e->tok << endl;
a7e58d4c
JS
3325 relaxed_p = false;
3326
3327 literal_number* n = new literal_number(value);
3328 n->tok = e->tok;
3329 n->visit (this);
10328bcf
JS
3330}
3331
3332void
3333const_folder::visit_logical_and_expr (logical_and_expr* e)
3334{
a7e58d4c
JS
3335 int64_t value;
3336 literal_number* left = get_number (e->left);
3337 literal_number* right = get_number (e->right);
3338
3339 if (left && right)
3340 value = left->value && right->value;
3341
3342 else if ((left && !left->value) || (right && !right->value))
3343 {
3344 // If the const is on the left, we get to short-circuit the right
3345 // immediately. Otherwise, we can only eliminate the LHS if it's pure.
3346 if (right)
3347 {
3348 varuse_collecting_visitor vu(session);
3349 e->left->visit(&vu);
3350 if (!vu.side_effect_free())
3351 {
3352 provide (e);
3353 return;
3354 }
3355 }
3356
3357 value = 0;
3358 }
3359
3360 // We might also get rid of useless "1&&x" and "x&&1", except it does
3361 // normalize x to 0 or 1. We could change it to "!!x", but it's not clear
3362 // that this would gain us much.
3363
3364 else
3365 {
3366 provide (e);
3367 return;
3368 }
3369
3370 if (session.verbose>2)
4af765b2 3371 clog << _("Collapsing constant logical-AND ") << *e->tok << endl;
a7e58d4c
JS
3372 relaxed_p = false;
3373
3374 literal_number* n = new literal_number(value);
3375 n->tok = e->tok;
3376 n->visit (this);
10328bcf
JS
3377}
3378
3379void
3380const_folder::visit_comparison (comparison* e)
3381{
f4869658
JS
3382 int comp;
3383
3384 literal_number *left_num, *right_num;
3385 literal_string *left_str, *right_str;
3386 get_literal(e->left, left_num, left_str);
3387 get_literal(e->right, right_num, right_str);
3388
3389 if (left_str && right_str)
3390 comp = left_str->value.compare(right_str->value);
3391
3392 else if (left_num && right_num)
3393 comp = left_num->value < right_num->value ? -1 :
3394 left_num->value > right_num->value ? 1 : 0;
3395
3396 else if ((left_num && ((left_num->value == LLONG_MIN &&
3397 (e->op == "<=" || e->op == ">")) ||
3398 (left_num->value == LLONG_MAX &&
3399 (e->op == ">=" || e->op == "<"))))
3400 ||
3401 (right_num && ((right_num->value == LLONG_MIN &&
3402 (e->op == ">=" || e->op == "<")) ||
3403 (right_num->value == LLONG_MAX &&
3404 (e->op == "<=" || e->op == ">")))))
3405 {
3406 expression* other = left_num ? e->right : e->left;
3407 varuse_collecting_visitor vu(session);
3408 other->visit(&vu);
3409 if (!vu.side_effect_free())
3410 provide (e);
3411 else
3412 {
3413 if (session.verbose>2)
4af765b2 3414 clog << _("Collapsing constant-boundary comparison ") << *e->tok << endl;
f4869658
JS
3415 relaxed_p = false;
3416
3417 // ops <= and >= are true, < and > are false
3418 literal_number* n = new literal_number( e->op.length() == 2 );
3419 n->tok = e->tok;
3420 n->visit (this);
3421 }
3422 return;
3423 }
3424
3425 else
3426 {
3427 provide (e);
3428 return;
3429 }
3430
3431 if (session.verbose>2)
4af765b2 3432 clog << _("Collapsing constant comparison ") << *e->tok << endl;
f4869658
JS
3433 relaxed_p = false;
3434
3435 int64_t value;
3436 if (e->op == "==")
3437 value = comp == 0;
3438 else if (e->op == "!=")
3439 value = comp != 0;
3440 else if (e->op == "<")
3441 value = comp < 0;
3442 else if (e->op == ">")
3443 value = comp > 0;
3444 else if (e->op == "<=")
3445 value = comp <= 0;
3446 else if (e->op == ">=")
3447 value = comp >= 0;
3448 else
4af765b2 3449 throw semantic_error (_("unsupported comparison operator ") + e->op);
f4869658
JS
3450
3451 literal_number* n = new literal_number(value);
3452 n->tok = e->tok;
3453 n->visit (this);
10328bcf
JS
3454}
3455
3456void
3457const_folder::visit_concatenation (concatenation* e)
3458{
29b1a9b7
JS
3459 literal_string* left = get_string (e->left);
3460 literal_string* right = get_string (e->right);
3461
3462 if (left && right)
3463 {
3464 if (session.verbose>2)
4af765b2 3465 clog << _("Collapsing constant concatenation ") << *e->tok << endl;
29b1a9b7
JS
3466 relaxed_p = false;
3467
3468 literal_string* n = new literal_string (*left);
3469 n->tok = e->tok;
3470 n->value.append(right->value);
3471 n->visit (this);
3472 }
3473 else if ((left && left->value.empty()) ||
3474 (right && right->value.empty()))
3475 {
3476 if (session.verbose>2)
4af765b2 3477 clog << _("Collapsing identity concatenation ") << *e->tok << endl;
29b1a9b7
JS
3478 relaxed_p = false;
3479 provide(left ? e->right : e->left);
3480 }
3481 else
3482 provide (e);
10328bcf
JS
3483}
3484
3485void
3486const_folder::visit_ternary_expression (ternary_expression* e)
3487{
3488 literal_number* cond = get_number (e->cond);
3489 if (!cond)
3490 {
3491 replace (e->truevalue);
3492 replace (e->falsevalue);
3493 provide (e);
3494 }
3495 else
3496 {
3497 if (session.verbose>2)
4af765b2
LB
3498 clog << _F("Collapsing constant-%" PRIi64 " ternary %s",
3499 cond->value, lex_cast(*e->tok).c_str()) << endl;
10328bcf
JS
3500 relaxed_p = false;
3501
3502 expression* n = cond->value ? e->truevalue : e->falsevalue;
3503 n->visit (this);
3504 }
3505}
3506
b7aedf26
JS
3507void
3508const_folder::visit_defined_op (defined_op* e)
3509{
3510 // If a @defined makes it this far, then it is, de facto, undefined.
3511
3512 if (session.verbose>2)
4af765b2 3513 clog << _("Collapsing untouched @defined check ") << *e->tok << endl;
b7aedf26
JS
3514 relaxed_p = false;
3515
3516 literal_number* n = new literal_number (0);
3517 n->tok = e->tok;
3518 n->visit (this);
3519}
3520
9fab2262
JS
3521void
3522const_folder::visit_target_symbol (target_symbol* e)
3523{
a45664f4 3524 if (session.skip_badvars)
9fab2262
JS
3525 {
3526 // Upon user request for ignoring context, the symbol is replaced
3527 // with a literal 0 and a warning message displayed
3528 // XXX this ignores possible side-effects, e.g. in array indexes
3529 literal_number* ln_zero = new literal_number (0);
3530 ln_zero->tok = e->tok;
3531 provide (ln_zero);
3532 if (!session.suppress_warnings)
4af765b2 3533 session.print_warning (_("Bad $context variable being substituted with literal 0"),
9fab2262
JS
3534 e->tok);
3535 else if (session.verbose > 2)
4af765b2 3536 clog << _("Bad $context variable being substituted with literal 0, ")
9fab2262
JS
3537 << *e->tok << endl;
3538 relaxed_p = false;
3539 }
3540 else
3541 update_visitor::visit_target_symbol (e);
3542}
3543
10328bcf
JS
3544static void semantic_pass_const_fold (systemtap_session& s, bool& relaxed_p)
3545{
3546 // Let's simplify statements with constant values.
3547
3548 const_folder cf (s, relaxed_p);
3549 // This instance may be reused for multiple probe/function body trims.
3550
3551 for (unsigned i=0; i<s.probes.size(); i++)
3552 cf.replace (s.probes[i]->body);
3553 for (map<string,functiondecl*>::iterator it = s.functions.begin();
3554 it != s.functions.end(); it++)
3555 cf.replace (it->second->body);
3556}
3557
3558
88bbd60d
DS
3559struct duplicate_function_remover: public functioncall_traversing_visitor
3560{
3561 systemtap_session& s;
88bbd60d
DS
3562 map<functiondecl*, functiondecl*>& duplicate_function_map;
3563
c214bd6a 3564 duplicate_function_remover(systemtap_session& sess,
88bbd60d 3565 map<functiondecl*, functiondecl*>&dfm):
c214bd6a 3566 s(sess), duplicate_function_map(dfm) {};
88bbd60d
DS
3567
3568 void visit_functioncall (functioncall* e);
3569};
3570
3571void
3572duplicate_function_remover::visit_functioncall (functioncall *e)
3573{
3574 functioncall_traversing_visitor::visit_functioncall (e);
3575
3576 // If the current function call reference points to a function that
3577 // is a duplicate, replace it.
3578 if (duplicate_function_map.count(e->referent) != 0)
3579 {
3580 if (s.verbose>2)
4af765b2
LB
3581 clog << _F("Changing %s reference to %s reference\n",
3582 e->referent->name.c_str(), duplicate_function_map[e->referent]->name.c_str());
88bbd60d
DS
3583 e->tok = duplicate_function_map[e->referent]->tok;
3584 e->function = duplicate_function_map[e->referent]->name;
3585 e->referent = duplicate_function_map[e->referent];
88bbd60d
DS
3586 }
3587}
3588
3589static string
3590get_functionsig (functiondecl* f)
3591{
3592 ostringstream s;
3593
3594 // Get the "name:args body" of the function in s. We have to
3595 // include the args since the function 'x1(a, b)' is different than
3596 // the function 'x2(b, a)' even if the bodies of the two functions
3597 // are exactly the same.
3598 f->printsig(s);
3599 f->body->print(s);
3600
3601 // printsig puts f->name + ':' on the front. Remove this
3602 // (otherwise, functions would never compare equal).
3603 string str = s.str().erase(0, f->name.size() + 1);
3604
3605 // Return the function signature.
3606 return str;
3607}
3608
bea72737 3609void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p)
88bbd60d
DS
3610{
3611 // Walk through all the functions, looking for duplicates.
3612 map<string, functiondecl*> functionsig_map;
3613 map<functiondecl*, functiondecl*> duplicate_function_map;
f76427a2
FCE
3614
3615
3616 vector<functiondecl*> newly_zapped_functions;
3617 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
88bbd60d 3618 {
f76427a2
FCE
3619 functiondecl *fd = it->second;
3620 string functionsig = get_functionsig(fd);
88bbd60d
DS
3621
3622 if (functionsig_map.count(functionsig) == 0)
c214bd6a
DS
3623 {
3624 // This function is unique. Remember it.
f76427a2 3625 functionsig_map[functionsig] = fd;
c214bd6a 3626 }
88bbd60d 3627 else
c214bd6a
DS
3628 {
3629 // This function is a duplicate.
f76427a2
FCE
3630 duplicate_function_map[fd] = functionsig_map[functionsig];
3631 newly_zapped_functions.push_back (fd);
c214bd6a 3632 relaxed_p = false;
c214bd6a 3633 }
88bbd60d 3634 }
f76427a2
FCE
3635 for (unsigned i=0; i<newly_zapped_functions.size(); i++)
3636 {
3637 map<string,functiondecl*>::iterator where = s.functions.find (newly_zapped_functions[i]->name);
3638 assert (where != s.functions.end());
3639 s.functions.erase (where);
3640 }
3641
88bbd60d
DS
3642
3643 // If we have duplicate functions, traverse down the tree, replacing
3644 // the appropriate function calls.
3645 // duplicate_function_remover::visit_functioncall() handles the
c214bd6a 3646 // details of replacing the function calls.
88bbd60d
DS
3647 if (duplicate_function_map.size() != 0)
3648 {
c214bd6a 3649 duplicate_function_remover dfr (s, duplicate_function_map);
88bbd60d
DS
3650
3651 for (unsigned i=0; i < s.probes.size(); i++)
3652 s.probes[i]->body->visit(&dfr);
3653 }
3654}
3655
cbfbbf69
FCE
3656
3657static int
c214bd6a 3658semantic_pass_optimize1 (systemtap_session& s)
cbfbbf69
FCE
3659{
3660 // In this pass, we attempt to rewrite probe/function bodies to
3661 // eliminate some blatantly unnecessary code. This is run before
3662 // type inference, but after symbol resolution and derived_probe
3663 // creation. We run an outer "relaxation" loop that repeats the
3664 // optimizations until none of them find anything to remove.
3665
3666 int rc = 0;
3667
3668 bool relaxed_p = false;
cfd621bc 3669 unsigned iterations = 0;
cbfbbf69
FCE
3670 while (! relaxed_p)
3671 {
85007c04 3672 if (pending_interrupts) break;
49abf162 3673
cbfbbf69
FCE
3674 relaxed_p = true; // until proven otherwise
3675
c0f56268
JS
3676 if (!s.unoptimized)
3677 {
3678 semantic_pass_opt1 (s, relaxed_p);
3679 semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0
3680 semantic_pass_opt3 (s, relaxed_p);
3681 semantic_pass_opt4 (s, relaxed_p);
3682 semantic_pass_opt5 (s, relaxed_p);
3683 }
3684
3685 // For listing mode, we need const-folding regardless of optimization so
3686 // that @defined expressions can be properly resolved. PR11360
ad12c592
MW
3687 // We also want it in case variables are used in if/case expressions,
3688 // so enable always. PR11366
3689 semantic_pass_const_fold (s, relaxed_p);
cfd621bc
FCE
3690
3691 iterations ++;
c214bd6a
DS
3692 }
3693
c214bd6a
DS
3694 return rc;
3695}
3696
3697
3698static int
3699semantic_pass_optimize2 (systemtap_session& s)
3700{
3701 // This is run after type inference. We run an outer "relaxation"
3702 // loop that repeats the optimizations until none of them find
3703 // anything to remove.
3704
3705 int rc = 0;
3706
3707 bool relaxed_p = false;
3708 while (! relaxed_p)
3709 {
85007c04 3710 if (pending_interrupts) break;
c214bd6a
DS
3711 relaxed_p = true; // until proven otherwise
3712
c0f56268
JS
3713 if (!s.unoptimized)
3714 semantic_pass_opt6 (s, relaxed_p);
cbfbbf69
FCE
3715 }
3716
cbfbbf69
FCE
3717 return rc;
3718}
3719
3720
3721
2b066ec1
FCE
3722// ------------------------------------------------------------------------
3723// type resolution
3724
3725
3726static int
3727semantic_pass_types (systemtap_session& s)
3728{
3729 int rc = 0;
3730
3731 // next pass: type inference
3732 unsigned iterations = 0;
3733 typeresolution_info ti (s);
57148ee7 3734
2b066ec1
FCE
3735 ti.assert_resolvability = false;
3736 // XXX: maybe convert to exception-based error signalling
3737 while (1)
3738 {
85007c04 3739 if (pending_interrupts) break;
49abf162 3740
2b066ec1 3741 iterations ++;
2b066ec1
FCE
3742 ti.num_newly_resolved = 0;
3743 ti.num_still_unresolved = 0;
3744
f76427a2 3745 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2b066ec1 3746 {
85007c04 3747 if (pending_interrupts) break;
49abf162 3748
f76427a2 3749 functiondecl* fd = it->second;
bdef2583 3750 ti.current_probe = 0;
f76427a2 3751 ti.current_function = fd;
8a43522c 3752 ti.t = pe_unknown;
f76427a2 3753 fd->body->visit (& ti);
8a43522c
GH
3754 // NB: we don't have to assert a known type for
3755 // functions here, to permit a "void" function.
3756 // The translator phase will omit the "retvalue".
3757 //
f76427a2
FCE
3758 // if (fd->type == pe_unknown)
3759 // ti.unresolved (fd->tok);
5abd364d
JS
3760 for (unsigned i=0; i < fd->locals.size(); ++i)
3761 ti.check_local (fd->locals[i]);
57148ee7 3762 }
2b066ec1
FCE
3763
3764 for (unsigned j=0; j<s.probes.size(); j++)
3765 {
85007c04 3766 if (pending_interrupts) break;
49abf162 3767
2b066ec1
FCE
3768 derived_probe* pn = s.probes[j];
3769 ti.current_function = 0;
bdef2583 3770 ti.current_probe = pn;
2b066ec1
FCE
3771 ti.t = pe_unknown;
3772 pn->body->visit (& ti);
5abd364d
JS
3773 for (unsigned i=0; i < pn->locals.size(); ++i)
3774 ti.check_local (pn->locals[i]);
5d23847d
FCE
3775
3776 probe_point* pp = pn->sole_location();
3777 if (pp->condition)
3778 {
3779 ti.current_function = 0;
3780 ti.current_probe = 0;
3781 ti.t = pe_long; // NB: expected type
3782 pp->condition->visit (& ti);
3783 }
2b066ec1
FCE
3784 }
3785
3786 for (unsigned j=0; j<s.globals.size(); j++)
3787 {
3788 vardecl* gd = s.globals[j];
3789 if (gd->type == pe_unknown)
3790 ti.unresolved (gd->tok);
3791 }
57148ee7 3792
2b066ec1 3793 if (ti.num_newly_resolved == 0) // converged
78f6bba6
FCE
3794 {
3795 if (ti.num_still_unresolved == 0)
3796 break; // successfully
3797 else if (! ti.assert_resolvability)
3798 ti.assert_resolvability = true; // last pass, with error msgs
3799 else
3800 { // unsuccessful conclusion
3801 rc ++;
3802 break;
3803 }
3804 }
2b066ec1 3805 }
57148ee7 3806
7e41d3dc 3807 return rc + s.num_errors();
2b066ec1
FCE
3808}
3809
3810
bdef2583
FCE
3811
3812typeresolution_info::typeresolution_info (systemtap_session& s):
3813 session(s), current_function(0), current_probe(0)
3814{
3815}
3816
3817
2b066ec1
FCE
3818void
3819typeresolution_info::visit_literal_number (literal_number* e)
3820{
3821 assert (e->type == pe_long);
3822 if ((t == e->type) || (t == pe_unknown))
3823 return;
3824
3825 mismatch (e->tok, e->type, t);
3826}
3827
3828
3829void
3830typeresolution_info::visit_literal_string (literal_string* e)
3831{
3832 assert (e->type == pe_string);
3833 if ((t == e->type) || (t == pe_unknown))
3834 return;
3835
3836 mismatch (e->tok, e->type, t);
3837}
3838
3839
3840void
3841typeresolution_info::visit_logical_or_expr (logical_or_expr *e)
3842{
3843 visit_binary_expression (e);
3844}
3845
3846
3847void
3848typeresolution_info::visit_logical_and_expr (logical_and_expr *e)
3849{
3850 visit_binary_expression (e);
3851}
3852
3853
3854void
3855typeresolution_info::visit_comparison (comparison *e)
3856{
d5d7c2cc 3857 // NB: result of any comparison is an integer!
553d27a5
FCE
3858 if (t == pe_stats || t == pe_string)
3859 invalid (e->tok, t);
3860
3861 t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown;
3862 e->left->visit (this);
3863 t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown;
3864 e->right->visit (this);
57148ee7 3865
553d27a5
FCE
3866 if (e->left->type != pe_unknown &&
3867 e->right->type != pe_unknown &&
3868 e->left->type != e->right->type)
3869 mismatch (e->tok, e->left->type, e->right->type);
57148ee7 3870
553d27a5
FCE
3871 if (e->type == pe_unknown)
3872 {
3873 e->type = pe_long;
3874 resolved (e->tok, e->type);
3875 }
2b066ec1
FCE
3876}
3877
3878
3879void
3880typeresolution_info::visit_concatenation (concatenation *e)
3881{
553d27a5
FCE
3882 if (t != pe_unknown && t != pe_string)
3883 invalid (e->tok, t);
3884
3885 t = pe_string;
3886 e->left->visit (this);
3887 t = pe_string;
3888 e->right->visit (this);
3889
3890 if (e->type == pe_unknown)
3891 {
3892 e->type = pe_string;
3893 resolved (e->tok, e->type);
3894 }
2b066ec1
FCE
3895}
3896
3897
2b066ec1
FCE
3898void
3899typeresolution_info::visit_assignment (assignment *e)
3900{
553d27a5
FCE
3901 if (t == pe_stats)
3902 invalid (e->tok, t);
2b066ec1 3903
2b066ec1
FCE
3904 if (e->op == "<<<") // stats aggregation
3905 {
553d27a5
FCE
3906 if (t == pe_string)
3907 invalid (e->tok, t);
3908
2b066ec1
FCE
3909 t = pe_stats;
3910 e->left->visit (this);
3911 t = pe_long;
3912 e->right->visit (this);
57b73400
GH
3913 if (e->type == pe_unknown ||
3914 e->type == pe_stats)
2b066ec1
FCE
3915 {
3916 e->type = pe_long;
3917 resolved (e->tok, e->type);
3918 }
3919 }
57b73400
GH
3920
3921 else if (e->left->type == pe_stats)
3922 invalid (e->left->tok, e->left->type);
3923
3924 else if (e->right->type == pe_stats)
3925 invalid (e->right->tok, e->right->type);
3926
553d27a5 3927 else if (e->op == "+=" || // numeric only
d5d7c2cc
FCE
3928 e->op == "-=" ||
3929 e->op == "*=" ||
3930 e->op == "/=" ||
3931 e->op == "%=" ||
3932 e->op == "&=" ||
3933 e->op == "^=" ||
3934 e->op == "|=" ||
3935 e->op == "<<=" ||
3936 e->op == ">>=" ||
553d27a5 3937 false)
2b066ec1 3938 {
553d27a5 3939 visit_binary_expression (e);
2b066ec1 3940 }
d5d7c2cc
FCE
3941 else if (e->op == ".=" || // string only
3942 false)
3943 {
3944 if (t == pe_long || t == pe_stats)
3945 invalid (e->tok, t);
3946
3947 t = pe_string;
3948 e->left->visit (this);
3949 t = pe_string;
3950 e->right->visit (this);
3951 if (e->type == pe_unknown)
3952 {
3953 e->type = pe_string;
3954 resolved (e->tok, e->type);
3955 }
3956 }
3957 else if (e->op == "=") // overloaded = for string & numeric operands
2b066ec1 3958 {
553d27a5 3959 // logic similar to ternary_expression
2b066ec1 3960 exp_type sub_type = t;
553d27a5
FCE
3961
3962 // Infer types across the l/r values
3963 if (sub_type == pe_unknown && e->type != pe_unknown)
2b066ec1 3964 sub_type = e->type;
553d27a5
FCE
3965
3966 t = (sub_type != pe_unknown) ? sub_type :
3967 (e->right->type != pe_unknown) ? e->right->type :
3968 pe_unknown;
2b066ec1 3969 e->left->visit (this);
553d27a5
FCE
3970 t = (sub_type != pe_unknown) ? sub_type :
3971 (e->left->type != pe_unknown) ? e->left->type :
3972 pe_unknown;
2b066ec1 3973 e->right->visit (this);
57148ee7 3974
553d27a5 3975 if ((sub_type != pe_unknown) && (e->type == pe_unknown))
2b066ec1
FCE
3976 {
3977 e->type = sub_type;
3978 resolved (e->tok, e->type);
3979 }
553d27a5 3980 if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
2b066ec1
FCE
3981 {
3982 e->type = e->left->type;
3983 resolved (e->tok, e->type);
3984 }
553d27a5
FCE
3985
3986 if (e->left->type != pe_unknown &&
3987 e->right->type != pe_unknown &&
3988 e->left->type != e->right->type)
3989 mismatch (e->tok, e->left->type, e->right->type);
d02548c0 3990
553d27a5 3991 }
d5d7c2cc 3992 else
4af765b2 3993 throw semantic_error (_("unsupported assignment operator ") + e->op);
553d27a5
FCE
3994}
3995
3996
7d902887
FCE
3997void
3998typeresolution_info::visit_embedded_expr (embedded_expr *e)
3999{
4000 if (e->type == pe_unknown)
4001 {
4002 if (e->code.find ("/* string */") != string::npos)
4003 e->type = pe_string;
4004 else // if (e->code.find ("/* long */") != string::npos)
4005 e->type = pe_long;
4006
4007 resolved (e->tok, e->type);
4008 }
4009}
4010
4011
553d27a5
FCE
4012void
4013typeresolution_info::visit_binary_expression (binary_expression* e)
4014{
4015 if (t == pe_stats || t == pe_string)
4016 invalid (e->tok, t);
4017
4018 t = pe_long;
4019 e->left->visit (this);
4020 t = pe_long;
4021 e->right->visit (this);
4022
4023 if (e->left->type != pe_unknown &&
4024 e->right->type != pe_unknown &&
4025 e->left->type != e->right->type)
4026 mismatch (e->tok, e->left->type, e->right->type);
57148ee7 4027
553d27a5
FCE
4028 if (e->type == pe_unknown)
4029 {
4030 e->type = pe_long;
4031 resolved (e->tok, e->type);
2b066ec1
FCE
4032 }
4033}
4034
4035
4036void
4037typeresolution_info::visit_pre_crement (pre_crement *e)
4038{
4039 visit_unary_expression (e);
4040}
4041
4042
4043void
4044typeresolution_info::visit_post_crement (post_crement *e)
4045{
4046 visit_unary_expression (e);
4047}
4048
4049
4050void
4051typeresolution_info::visit_unary_expression (unary_expression* e)
4052{
553d27a5
FCE
4053 if (t == pe_stats || t == pe_string)
4054 invalid (e->tok, t);
4055
2b066ec1
FCE
4056 t = pe_long;
4057 e->operand->visit (this);
4058
553d27a5 4059 if (e->type == pe_unknown)
2b066ec1
FCE
4060 {
4061 e->type = pe_long;
4062 resolved (e->tok, e->type);
4063 }
4064}
4065
4066
2b066ec1
FCE
4067void
4068typeresolution_info::visit_ternary_expression (ternary_expression* e)
4069{
4070 exp_type sub_type = t;
4071
4072 t = pe_long;
4073 e->cond->visit (this);
4074
553d27a5 4075 // Infer types across the true/false arms of the ternary expression.
2b066ec1
FCE
4076
4077 if (sub_type == pe_unknown && e->type != pe_unknown)
4078 sub_type = e->type;
4079 t = sub_type;
4080 e->truevalue->visit (this);
4081 t = sub_type;
4082 e->falsevalue->visit (this);
4083
4084 if ((sub_type == pe_unknown) && (e->type != pe_unknown))
4085 ; // already resolved
4086 else if ((sub_type != pe_unknown) && (e->type == pe_unknown))
4087 {
4088 e->type = sub_type;
4089 resolved (e->tok, e->type);
4090 }
4091 else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown))
4092 {
4093 e->type = e->truevalue->type;
4094 resolved (e->tok, e->type);
4095 }
4096 else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown))
4097 {
4098 e->type = e->falsevalue->type;
4099 resolved (e->tok, e->type);
4100 }
4101 else if (e->type != sub_type)
4102 mismatch (e->tok, sub_type, e->type);
4103}
4104
4105
4106template <class Referrer, class Referent>
4107void resolve_2types (Referrer* referrer, Referent* referent,
31966088 4108 typeresolution_info* r, exp_type t, bool accept_unknown = false)
2b066ec1
FCE
4109{
4110 exp_type& re_type = referrer->type;
4111 const token* re_tok = referrer->tok;
4112 exp_type& te_type = referent->type;
4113 const token* te_tok = referent->tok;
4114
4115 if (t != pe_unknown && re_type == t && re_type == te_type)
4116 ; // do nothing: all three e->types in agreement
4117 else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type)
4118 ; // do nothing: two known e->types in agreement
4119 else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type)
4120 r->mismatch (re_tok, re_type, te_type);
4121 else if (re_type != pe_unknown && t != pe_unknown && re_type != t)
4122 r->mismatch (re_tok, re_type, t);
4123 else if (te_type != pe_unknown && t != pe_unknown && te_type != t)
4124 r->mismatch (te_tok, te_type, t);
4125 else if (re_type == pe_unknown && t != pe_unknown)
4126 {
4127 // propagate from upstream
4128 re_type = t;
4129 r->resolved (re_tok, re_type);
4130 // catch re_type/te_type mismatch later
4131 }
4132 else if (re_type == pe_unknown && te_type != pe_unknown)
4133 {
4134 // propagate from referent
4135 re_type = te_type;
4136 r->resolved (re_tok, re_type);
4137 // catch re_type/t mismatch later
4138 }
4139 else if (re_type != pe_unknown && te_type == pe_unknown)
4140 {
4141 // propagate to referent
4142 te_type = re_type;
4143 r->resolved (te_tok, te_type);
4144 // catch re_type/t mismatch later
4145 }
31966088 4146 else if (! accept_unknown)
2b066ec1
FCE
4147 r->unresolved (re_tok);
4148}
4149
4150
4151void
4152typeresolution_info::visit_symbol (symbol* e)
4153{
4154 assert (e->referent != 0);
d02548c0 4155 resolve_2types (e, e->referent, this, t);
2b066ec1
FCE
4156}
4157
4158
d7f3e0c5
GH
4159void
4160typeresolution_info::visit_target_symbol (target_symbol* e)
4161{
cbfbbf69
FCE
4162 // This occurs only if a target symbol was not resolved over in
4163 // tapset.cxx land, that error was properly suppressed, and the
4164 // later unused-expression-elimination pass didn't get rid of it
4165 // either. So we have a target symbol that is believed to be of
4166 // genuine use, yet unresolved by the provider.
ba6f838d
FCE
4167
4168 if (session.verbose > 2)
4169 {
4af765b2 4170 clog << _("Resolution problem with ");
ba6f838d
FCE
4171 if (current_function)
4172 {
4173 clog << "function " << current_function->name << endl;
4174 current_function->body->print (clog);
4175 clog << endl;
4176 }
4177 else if (current_probe)
4178 {
da2df842 4179 clog << "probe " << *current_probe->sole_location() << endl;
ba6f838d
FCE
4180 current_probe->body->print (clog);
4181 clog << endl;
4182 }
57148ee7 4183 else
4af765b2
LB
4184 //TRANSLATORS: simply saying not an issue with a probe or function
4185 clog << _("other") << endl;
ba6f838d
FCE
4186 }
4187
9b48ce88
FCE
4188 if (e->saved_conversion_error)
4189 throw (* (e->saved_conversion_error));
4190 else
4af765b2 4191 throw semantic_error(_("unresolved target-symbol expression"), e->tok);
d7f3e0c5
GH
4192}
4193
4194
30263a73
FCE
4195void
4196typeresolution_info::visit_defined_op (defined_op* e)
4197{
4af765b2 4198 throw semantic_error(_("unexpected @defined"), e->tok);
30263a73
FCE
4199}
4200
4201
8cc799a5
JS
4202void
4203typeresolution_info::visit_entry_op (entry_op* e)
4204{
4af765b2 4205 throw semantic_error(_("@entry is only valid in .return probes"), e->tok);
8cc799a5
JS
4206}
4207
4208
9b5af295
JS
4209void
4210typeresolution_info::visit_cast_op (cast_op* e)
4211{
4212 // Like target_symbol, a cast_op shouldn't survive this far
4213 // unless it was not resolved and its value is really needed.
4214 if (e->saved_conversion_error)
4215 throw (* (e->saved_conversion_error));
4216 else
4af765b2
LB
4217 throw semantic_error(_F("type definition '%s' not found",
4218 e->type_name.c_str()), e->tok);
9b5af295
JS
4219}
4220
4221
2b066ec1
FCE
4222void
4223typeresolution_info::visit_arrayindex (arrayindex* e)
4224{
2b066ec1 4225
d02548c0
GH
4226 symbol *array = NULL;
4227 hist_op *hist = NULL;
4228 classify_indexable(e->base, array, hist);
57148ee7 4229
d02548c0
GH
4230 // Every hist_op has type [int]:int, that is to say, every hist_op
4231 // is a pseudo-one-dimensional integer array type indexed by
4232 // integers (bucket numbers).
4233
4234 if (hist)
4235 {
4236 if (e->indexes.size() != 1)
4237 unresolved (e->tok);
4238 t = pe_long;
4239 e->indexes[0]->visit (this);
4240 if (e->indexes[0]->type != pe_long)
4241 unresolved (e->tok);
a4636912 4242 hist->visit (this);
1bbeef03
GH
4243 if (e->type != pe_long)
4244 {
4245 e->type = pe_long;
4246 resolved (e->tok, pe_long);
4247 }
d02548c0
GH
4248 return;
4249 }
4250
4251 // Now we are left with "normal" map inference and index checking.
4252
4253 assert (array);
4254 assert (array->referent != 0);
4255 resolve_2types (e, array->referent, this, t);
2b066ec1
FCE
4256
4257 // now resolve the array indexes
69c68955
FCE
4258
4259 // if (e->referent->index_types.size() == 0)
4260 // // redesignate referent as array
4261 // e->referent->set_arity (e->indexes.size ());
2b066ec1 4262
d02548c0 4263 if (e->indexes.size() != array->referent->index_types.size())
2b066ec1
FCE
4264 unresolved (e->tok); // symbol resolution should prevent this
4265 else for (unsigned i=0; i<e->indexes.size(); i++)
4266 {
4267 expression* ee = e->indexes[i];
d02548c0 4268 exp_type& ft = array->referent->index_types [i];
2b066ec1
FCE
4269 t = ft;
4270 ee->visit (this);
4271 exp_type at = ee->type;
4272
4273 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
4274 {
4275 // propagate to formal type
4276 ft = at;
d02548c0 4277 resolved (array->referent->tok, ft);
2b066ec1
FCE
4278 // uses array decl as there is no token for "formal type"
4279 }
4280 if (at == pe_stats)
4281 invalid (ee->tok, at);
4282 if (ft == pe_stats)
4283 invalid (ee->tok, ft);
4284 if (at != pe_unknown && ft != pe_unknown && ft != at)
4285 mismatch (e->tok, at, ft);
4286 if (at == pe_unknown)
313b2f74 4287 unresolved (ee->tok);
2b066ec1
FCE
4288 }
4289}
4290
4291
4292void
4293typeresolution_info::visit_functioncall (functioncall* e)
4294{
4295 assert (e->referent != 0);
4296
57148ee7 4297 resolve_2types (e, e->referent, this, t, true); // accept unknown type
2b066ec1
FCE
4298
4299 if (e->type == pe_stats)
4300 invalid (e->tok, e->type);
4301
2b066ec1
FCE
4302 // now resolve the function parameters
4303 if (e->args.size() != e->referent->formal_args.size())
4304 unresolved (e->tok); // symbol resolution should prevent this
4305 else for (unsigned i=0; i<e->args.size(); i++)
4306 {
4307 expression* ee = e->args[i];
4308 exp_type& ft = e->referent->formal_args[i]->type;
4309 const token* fe_tok = e->referent->formal_args[i]->tok;
4310 t = ft;
4311 ee->visit (this);
4312 exp_type at = ee->type;
57148ee7 4313
2b066ec1
FCE
4314 if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown)
4315 {
4316 // propagate to formal arg
4317 ft = at;
4318 resolved (e->referent->formal_args[i]->tok, ft);
4319 }
4320 if (at == pe_stats)
4321 invalid (e->tok, at);
4322 if (ft == pe_stats)
4323 invalid (fe_tok, ft);
4324 if (at != pe_unknown && ft != pe_unknown && ft != at)
4325 mismatch (e->tok, at, ft);
4326 if (at == pe_unknown)
4327 unresolved (e->tok);
4328 }
4329}
4330
4331
4332void
4333typeresolution_info::visit_block (block* e)
4334{
4335 for (unsigned i=0; i<e->statements.size(); i++)
4336 {
57148ee7 4337 try
2b066ec1
FCE
4338 {
4339 t = pe_unknown;
4340 e->statements[i]->visit (this);
4341 }
4342 catch (const semantic_error& e)
4343 {
4344 session.print_error (e);
4345 }
4346 }
4347}
4348
4349
f4fe2e93
FCE
4350void
4351typeresolution_info::visit_try_block (try_block* e)
4352{
4353 if (e->try_block)
4354 e->try_block->visit (this);
4355 if (e->catch_error_var)
4356 {
4357 t = pe_string;
4358 e->catch_error_var->visit (this);
4359 }
4360 if (e->catch_block)
4361 e->catch_block->visit (this);
4362}
4363
4364
54dfabe9 4365void
6a80494e 4366typeresolution_info::visit_embeddedcode (embeddedcode* s)
54dfabe9 4367{
6a80494e
FCE
4368 // PR11573. If we have survived thus far with a piece of embedded
4369 // code that requires uprobes, we need to track this.
4370 //
4371 // This is an odd place for this check, as opposed
4372 // to a separate 'optimization' pass, or c_unparser::visit_embeddedcode
4373 // over yonder in pass 3. However, we want to do it during pass 2 so
4374 // that cached sessions also get the uprobes treatment.
4375 if (!session.need_uprobes && s->code.find("/* pragma:uprobes */") != string::npos)
4376 {
4377 if (session.verbose > 2)
4af765b2 4378 clog << _("Activating uprobes support because /* pragma:uprobes */ seen.") << endl;
6a80494e
FCE
4379 session.need_uprobes = true;
4380 }
54dfabe9
FCE
4381}
4382
4383
2b066ec1
FCE
4384void
4385typeresolution_info::visit_if_statement (if_statement* e)
4386{
4387 t = pe_long;
4388 e->condition->visit (this);
4389
4390 t = pe_unknown;
4391 e->thenblock->visit (this);
4392
4393 if (e->elseblock)
4394 {
4395 t = pe_unknown;
4396 e->elseblock->visit (this);
4397 }
4398}
4399
4400
4401void
4402typeresolution_info::visit_for_loop (for_loop* e)
4403{
4404 t = pe_unknown;
cbfbbf69 4405 if (e->init) e->init->visit (this);
2b066ec1
FCE
4406 t = pe_long;
4407 e->cond->visit (this);
4408 t = pe_unknown;
57148ee7 4409 if (e->incr) e->incr->visit (this);
2b066ec1 4410 t = pe_unknown;
57148ee7 4411 e->block->visit (this);
2b066ec1
FCE
4412}
4413
4414
69c68955
FCE
4415void
4416typeresolution_info::visit_foreach_loop (foreach_loop* e)
4417{
4418 // See also visit_arrayindex.
4419 // This is different in that, being a statement, we can't assign
4420 // a type to the outer array, only propagate to/from the indexes
4421
4422 // if (e->referent->index_types.size() == 0)
4423 // // redesignate referent as array
4424 // e->referent->set_arity (e->indexes.size ());
4425
c261711d 4426 exp_type wanted_value = pe_unknown;
d02548c0
GH
4427 symbol *array = NULL;
4428 hist_op *hist = NULL;
4429 classify_indexable(e->base, array, hist);
69c68955 4430
d02548c0 4431 if (hist)
57148ee7 4432 {
d02548c0
GH
4433 if (e->indexes.size() != 1)
4434 unresolved (e->tok);
4435 t = pe_long;
4436 e->indexes[0]->visit (this);
4437 if (e->indexes[0]->type != pe_long)
4438 unresolved (e->tok);
a4636912 4439 hist->visit (this);
c261711d 4440 wanted_value = pe_long;
d02548c0
GH
4441 }
4442 else
4443 {
57148ee7 4444 assert (array);
d02548c0
GH
4445 if (e->indexes.size() != array->referent->index_types.size())
4446 unresolved (e->tok); // symbol resolution should prevent this
4447 else for (unsigned i=0; i<e->indexes.size(); i++)
4448 {
4449 expression* ee = e->indexes[i];
4450 exp_type& ft = array->referent->index_types [i];
4451 t = ft;
4452 ee->visit (this);
4453 exp_type at = ee->type;
57148ee7 4454
d02548c0
GH
4455 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
4456 {
4457 // propagate to formal type
4458 ft = at;
4459 resolved (array->referent->tok, ft);
4460 // uses array decl as there is no token for "formal type"
4461 }
4462 if (at == pe_stats)
4463 invalid (ee->tok, at);
4464 if (ft == pe_stats)
4465 invalid (ee->tok, ft);
4466 if (at != pe_unknown && ft != pe_unknown && ft != at)
4467 mismatch (e->tok, at, ft);
4468 if (at == pe_unknown)
4469 unresolved (ee->tok);
4470 }
c261711d
JS
4471 t = pe_unknown;
4472 array->visit (this);
4473 wanted_value = array->type;
4474 }
4475
4476 if (e->value)
4477 {
4478 if (wanted_value == pe_stats)
4479 invalid(e->value->tok, wanted_value);
4480 else if (wanted_value != pe_unknown)
4481 check_arg_type(wanted_value, e->value);
4482 else
4483 {
4484 t = pe_unknown;
4485 e->value->visit (this);
4486 }
69c68955
FCE
4487 }
4488
27f21e8c
DS
4489 if (e->limit)
4490 {
4491 t = pe_long;
4492 e->limit->visit (this);
4493 }
4494
69c68955 4495 t = pe_unknown;
57148ee7 4496 e->block->visit (this);
69c68955
FCE
4497}
4498
4499
2b066ec1 4500void
78f6bba6 4501typeresolution_info::visit_null_statement (null_statement*)
2b066ec1
FCE
4502{
4503}
4504
4505
4506void
4507typeresolution_info::visit_expr_statement (expr_statement* e)
4508{
4509 t = pe_unknown;
4510 e->value->visit (this);
4511}
4512
4513
57148ee7 4514struct delete_statement_typeresolution_info:
d98d459c
GH
4515 public throwing_visitor
4516{
4517 typeresolution_info *parent;
4518 delete_statement_typeresolution_info (typeresolution_info *p):
4af765b2 4519 throwing_visitor (_("invalid operand of delete expression")),
d98d459c
GH
4520 parent (p)
4521 {}
4522
4523 void visit_arrayindex (arrayindex* e)
4524 {
4525 parent->visit_arrayindex (e);
4526 }
57148ee7 4527
d98d459c
GH
4528 void visit_symbol (symbol* e)
4529 {
4530 exp_type ignored = pe_unknown;
57148ee7 4531 assert (e->referent != 0);
d98d459c
GH
4532 resolve_2types (e, e->referent, parent, ignored);
4533 }
4534};
4535
4536
2b066ec1
FCE
4537void
4538typeresolution_info::visit_delete_statement (delete_statement* e)
4539{
d98d459c
GH
4540 delete_statement_typeresolution_info di (this);
4541 t = pe_unknown;
4542 e->value->visit (&di);
2b066ec1
FCE
4543}
4544
4545
f3c26ea5 4546void
78f6bba6 4547typeresolution_info::visit_next_statement (next_statement*)
f3c26ea5
FCE
4548{
4549}
4550
4551
4552void
78f6bba6 4553typeresolution_info::visit_break_statement (break_statement*)
f3c26ea5
FCE
4554{
4555}
4556
4557
4558void
78f6bba6 4559typeresolution_info::visit_continue_statement (continue_statement*)
f3c26ea5
FCE
4560{
4561}
4562
4563
2b066ec1
FCE
4564void
4565typeresolution_info::visit_array_in (array_in* e)
4566{
ce10591c
FCE
4567 // all unary operators only work on numerics
4568 exp_type t1 = t;
4569 t = pe_unknown; // array value can be anything
4570 e->operand->visit (this);
4571
4572 if (t1 == pe_unknown && e->type != pe_unknown)
4573 ; // already resolved
4574 else if (t1 == pe_string || t1 == pe_stats)
4575 mismatch (e->tok, t1, pe_long);
4576 else if (e->type == pe_unknown)
4577 {
4578 e->type = pe_long;
4579 resolved (e->tok, e->type);
4580 }
2b066ec1
FCE
4581}
4582
4583
4584void
4585typeresolution_info::visit_return_statement (return_statement* e)
4586{
4587 // This is like symbol, where the referent is
4588 // the return value of the function.
4589
57148ee7 4590 // translation pass will print error
2b066ec1 4591 if (current_function == 0)
22f46231 4592 return;
2b066ec1
FCE
4593
4594 exp_type& e_type = current_function->type;
4595 t = current_function->type;
4596 e->value->visit (this);
4597
4598 if (e_type != pe_unknown && e->value->type != pe_unknown
4599 && e_type != e->value->type)
4600 mismatch (current_function->tok, e_type, e->value->type);
57148ee7 4601 if (e_type == pe_unknown &&
2b066ec1
FCE
4602 (e->value->type == pe_long || e->value->type == pe_string))
4603 {
4604 // propagate non-statistics from value
4605 e_type = e->value->type;
4606 resolved (current_function->tok, e->value->type);
4607 }
4608 if (e->value->type == pe_stats)
4609 invalid (e->value->tok, e->value->type);
4610}
4611
57148ee7 4612void
d02548c0
GH
4613typeresolution_info::visit_print_format (print_format* e)
4614{
4615 size_t unresolved_args = 0;
4616
1bbeef03
GH
4617 if (e->hist)
4618 {
4619 e->hist->visit(this);
4620 }
4621
4622 else if (e->print_with_format)
d02548c0
GH
4623 {
4624 // If there's a format string, we can do both inference *and*
4625 // checking.
4626
4627 // First we extract the subsequence of formatting components
4628 // which are conversions (not just literal string components)
4629
34201621 4630 unsigned expected_num_args = 0;
d02548c0
GH
4631 std::vector<print_format::format_component> components;
4632 for (size_t i = 0; i < e->components.size(); ++i)
4633 {
4634 if (e->components[i].type == print_format::conv_unspecified)
4af765b2 4635 throw semantic_error (_("Unspecified conversion in print operator format string"),
d02548c0 4636 e->tok);
b5852334 4637 else if (e->components[i].type == print_format::conv_literal)
d02548c0
GH
4638 continue;
4639 components.push_back(e->components[i]);
34201621
DB
4640 ++expected_num_args;
4641 if (e->components[i].widthtype == print_format::width_dynamic)
4642 ++expected_num_args;
4643 if (e->components[i].prectype == print_format::prec_dynamic)
4644 ++expected_num_args;
d02548c0
GH
4645 }
4646
4647 // Then we check that the number of conversions and the number
4648 // of args agree.
4649
34201621 4650 if (expected_num_args != e->args.size())
4af765b2 4651 throw semantic_error (_("Wrong number of args to formatted print operator"),
d02548c0
GH
4652 e->tok);
4653
4654 // Then we check that the types of the conversions match the types
4655 // of the args.
34201621 4656 unsigned argno = 0;
d02548c0
GH
4657 for (size_t i = 0; i < components.size(); ++i)
4658 {
34201621
DB
4659 // Check the dynamic width, if specified
4660 if (components[i].widthtype == print_format::width_dynamic)
4661 {
4662 check_arg_type (pe_long, e->args[argno]);
4663 ++argno;
4664 }
4665
4666 // Check the dynamic precision, if specified
4667 if (components[i].prectype == print_format::prec_dynamic)
4668 {
4669 check_arg_type (pe_long, e->args[argno]);
4670 ++argno;
4671 }
4672
d02548c0
GH
4673 exp_type wanted = pe_unknown;
4674
4675 switch (components[i].type)
4676 {
d02548c0
GH
4677 case print_format::conv_unspecified:
4678 case print_format::conv_literal:
4679 assert (false);
4680 break;
4681
4682 case print_format::conv_signed_decimal:
4683 case print_format::conv_unsigned_decimal:
4684 case print_format::conv_unsigned_octal:
58cf0567 4685 case print_format::conv_unsigned_ptr:
d02548c0
GH
4686 case print_format::conv_unsigned_uppercase_hex:
4687 case print_format::conv_unsigned_lowercase_hex:
dc0b623a 4688 case print_format::conv_binary:
fecccf83 4689 case print_format::conv_char:
ec03bd4b 4690 case print_format::conv_memory:
30c94a80 4691 case print_format::conv_memory_hex:
d02548c0
GH
4692 wanted = pe_long;
4693 break;
4694
4695 case print_format::conv_string:
4696 wanted = pe_string;
4697 break;
4698 }
4699
4700 assert (wanted != pe_unknown);
34201621
DB
4701 check_arg_type (wanted, e->args[argno]);
4702 ++argno;
d02548c0
GH
4703 }
4704 }
4705 else
4706 {
4707 // Without a format string, the best we can do is require that
4708 // each argument resolve to a concrete type.
4709 for (size_t i = 0; i < e->args.size(); ++i)
4710 {
4711 t = pe_unknown;
4712 e->args[i]->visit (this);
4713 if (e->args[i]->type == pe_unknown)
4714 {
4715 unresolved (e->args[i]->tok);
4716 ++unresolved_args;
4717 }
4718 }
4719 }
57148ee7 4720
d02548c0
GH
4721 if (unresolved_args == 0)
4722 {
4723 if (e->type == pe_unknown)
4724 {
4725 if (e->print_to_stream)
4726 e->type = pe_long;
4727 else
57148ee7 4728 e->type = pe_string;
d02548c0
GH
4729 resolved (e->tok, e->type);
4730 }
4731 }
4732 else
4733 {
4734 e->type = pe_unknown;
4735 unresolved (e->tok);
4736 }
4737}
4738
4739
57148ee7 4740void
d02548c0
GH
4741typeresolution_info::visit_stat_op (stat_op* e)
4742{
4743 t = pe_stats;
4744 e->stat->visit (this);
4745 if (e->type == pe_unknown)
4746 {
4747 e->type = pe_long;
4748 resolved (e->tok, e->type);
4749 }
07c17d67 4750 else if (e->type != pe_long)
d02548c0
GH
4751 mismatch (e->tok, e->type, pe_long);
4752}
4753
57148ee7 4754void
d02548c0
GH
4755typeresolution_info::visit_hist_op (hist_op* e)
4756{
4757 t = pe_stats;
4758 e->stat->visit (this);
4759}
4760
2b066ec1 4761
34201621
DB
4762void
4763typeresolution_info::check_arg_type (exp_type wanted, expression* arg)
4764{
4765 t = wanted;
4766 arg->visit (this);
4767
4768 if (arg->type == pe_unknown)
4769 {
4770 arg->type = wanted;
4771 resolved (arg->tok, wanted);
4772 }
4773 else if (arg->type != wanted)
4774 {
4775 mismatch (arg->tok, arg->type, wanted);
4776 }
4777}
4778
4779
5abd364d
JS
4780void
4781typeresolution_info::check_local (vardecl* v)
4782{
4783 if (v->arity != 0)
4784 {
4785 num_still_unresolved ++;
4786 if (assert_resolvability)
4787 session.print_error
4af765b2 4788 (semantic_error (_("array locals not supported, missing global declaration? "), v->tok));
5abd364d
JS
4789 }
4790
4791 if (v->type == pe_unknown)
4792 unresolved (v->tok);
4793 else if (v->type == pe_stats)
4794 {
4795 num_still_unresolved ++;
4796 if (assert_resolvability)
4797 session.print_error
4af765b2 4798 (semantic_error (_("stat locals not supported, missing global declaration? "), v->tok));
5abd364d
JS
4799 }
4800 else if (!(v->type == pe_long || v->type == pe_string))
4801 invalid (v->tok, v->type);
4802}
4803
4804
2b066ec1
FCE
4805void
4806typeresolution_info::unresolved (const token* tok)
4807{
4808 num_still_unresolved ++;
4809
4810 if (assert_resolvability)
4811 {
6c543717 4812 stringstream msg;
4af765b2 4813 msg << _("unresolved type ");
6c543717 4814 session.print_error (semantic_error (msg.str(), tok));
2b066ec1
FCE
4815 }
4816}
4817
4818
4819void
4820typeresolution_info::invalid (const token* tok, exp_type pe)
4821{
4822 num_still_unresolved ++;
4823
4824 if (assert_resolvability)
4825 {
6c543717 4826 stringstream msg;
022b623f 4827 if (tok && tok->type == tok_operator)
4af765b2 4828 msg << _("invalid operator");
2b066ec1 4829 else
4af765b2 4830 msg << _("invalid type ") << pe;
6c543717 4831 session.print_error (semantic_error (msg.str(), tok));
2b066ec1
FCE
4832 }
4833}
4834
4835
4836void
4837typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
4838{
d784c94d 4839 bool tok_resolved = false;
d5f0c423
RA
4840 size_t i;
4841 semantic_error* err1 = 0;
2b066ec1
FCE
4842 num_still_unresolved ++;
4843
d5f0c423
RA
4844 //BZ 9719: for improving type mismatch messages, a semantic error is
4845 //generated with the token where type was first resolved. All such
4846 //resolved tokens, stored in a vector, are matched against their
4847 //content. If an error for the matching token hasn't been printed out
4848 //already, it is and the token pushed in another printed_toks vector
4849
2b066ec1
FCE
4850 if (assert_resolvability)
4851 {
6c543717 4852 stringstream msg;
d5f0c423
RA
4853 for (i=0; i<resolved_toks.size(); i++)
4854 {
4855 if (resolved_toks[i]->content == tok->content)
4856 {
4857 tok_resolved = true;
4858 break;
4859 }
4860 }
4861 if (!tok_resolved)
4862 {
4af765b2
LB
4863 msg << _F("type mismatch ( %s vs. %s )",
4864 lex_cast(t1).c_str(), lex_cast(t2).c_str());
d5f0c423
RA
4865 }
4866 else
4867 {
d784c94d 4868 bool tok_printed = false;
d5f0c423
RA
4869 for (size_t j=0; j<printed_toks.size(); j++)
4870 {
4871 if (printed_toks[j] == resolved_toks[i])
4872 {
4873 tok_printed = true;
4874 break;
4875 }
4876 }
4af765b2
LB
4877 msg << _F("type mismatch ( %s vs. %s )",
4878 lex_cast(t1).c_str(), lex_cast(t2).c_str());
d5f0c423
RA
4879 if (!tok_printed)
4880 {
4881 //error for possible mismatch in the earlier resolved token
4882 printed_toks.push_back (resolved_toks[i]);
4883 stringstream type_msg;
4af765b2 4884 type_msg << _F("type was first inferred here ( %s )", lex_cast(t2).c_str());
d5f0c423
RA
4885 err1 = new semantic_error (type_msg.str(), resolved_toks[i]);
4886 }
4887 }
4888 semantic_error err (msg.str(), tok);
4889 err.chain = err1;
4890 session.print_error (err);
2b066ec1
FCE
4891 }
4892}
4893
4894
4895void
d5f0c423 4896typeresolution_info::resolved (const token* tok, exp_type)
2b066ec1 4897{
d5f0c423 4898 resolved_toks.push_back (tok);
2b066ec1 4899 num_newly_resolved ++;
2b066ec1
FCE
4900}
4901
73267b89 4902/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.73319 seconds and 5 git commands to generate.