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