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