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