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