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