]>
Commit | Line | Data |
---|---|---|
2b066ec1 | 1 | // elaboration functions |
3e3756f8 | 2 | // Copyright (C) 2005-2016 Red Hat Inc. |
1773fd03 | 3 | // Copyright (C) 2008 Intel Corporation |
69c68955 FCE |
4 | // |
5 | // This file is part of systemtap, and is free software. You can | |
6 | // redistribute it and/or modify it under the terms of the GNU General | |
7 | // Public License (GPL); either version 2, or (at your option) any | |
8 | // later version. | |
2b066ec1 FCE |
9 | |
10 | #include "config.h" | |
11 | #include "elaborate.h" | |
2865d17a | 12 | #include "translate.h" |
2b066ec1 | 13 | #include "parse.h" |
20c6c071 | 14 | #include "tapsets.h" |
dc38c0ae | 15 | #include "session.h" |
72dbc915 | 16 | #include "util.h" |
a057c85c | 17 | #include "task_finder.h" |
60cf5fae | 18 | #include "stapregex.h" |
a3e980f9 | 19 | #include "stringtable.h" |
d2548fe7 | 20 | |
2b066ec1 FCE |
21 | extern "C" { |
22 | #include <sys/utsname.h> | |
a477f3f1 | 23 | #include <fnmatch.h> |
4af765b2 LB |
24 | #define __STDC_FORMAT_MACROS |
25 | #include <inttypes.h> | |
2b066ec1 FCE |
26 | } |
27 | ||
2b066ec1 | 28 | #include <algorithm> |
67c0a579 GH |
29 | #include <fstream> |
30 | #include <map> | |
29e64872 | 31 | #include <cassert> |
67c0a579 GH |
32 | #include <set> |
33 | #include <vector> | |
1b07c728 FCE |
34 | #include <algorithm> |
35 | #include <iterator> | |
f4869658 | 36 | #include <climits> |
1b07c728 | 37 | |
2b066ec1 | 38 | |
2b066ec1 FCE |
39 | using namespace std; |
40 | ||
41 | ||
42 | // ------------------------------------------------------------------------ | |
43 | ||
5d23847d FCE |
44 | // Used in probe_point condition construction. Either argument may be |
45 | // NULL; if both, return NULL too. Resulting expression is a deep | |
46 | // copy for symbol resolution purposes. | |
47 | expression* add_condition (expression* a, expression* b) | |
48 | { | |
49 | if (!a && !b) return 0; | |
50 | if (! a) return deep_copy_visitor::deep_copy(b); | |
51 | if (! b) return deep_copy_visitor::deep_copy(a); | |
52 | logical_and_expr la; | |
53 | la.op = "&&"; | |
54 | la.left = a; | |
55 | la.right = b; | |
56 | la.tok = a->tok; // or could be b->tok | |
57 | return deep_copy_visitor::deep_copy(& la); | |
58 | } | |
59 | ||
60 | // ------------------------------------------------------------------------ | |
61 | ||
62 | ||
2b066ec1 | 63 | |
4c5d1300 | 64 | derived_probe::derived_probe (probe *p, probe_point *l, bool rewrite_loc): |
ca6d3b0f JL |
65 | base (p), base_pp(l), group(NULL), sdt_semaphore_addr(0), |
66 | session_index((unsigned)-1) | |
2b066ec1 | 67 | { |
5d23847d FCE |
68 | assert (p); |
69 | this->tok = p->tok; | |
70 | this->privileged = p->privileged; | |
71 | this->body = deep_copy_visitor::deep_copy(p->body); | |
cbbe8080 | 72 | |
5d23847d | 73 | assert (l); |
4c5d1300 JS |
74 | // make a copy for subclasses which want to rewrite the location |
75 | if (rewrite_loc) | |
76 | l = new probe_point(*l); | |
5d23847d | 77 | this->locations.push_back (l); |
2b066ec1 FCE |
78 | } |
79 | ||
98afd80e | 80 | |
b8da0ad1 FCE |
81 | void |
82 | derived_probe::printsig (ostream& o) const | |
83 | { | |
84 | probe::printsig (o); | |
85 | printsig_nested (o); | |
86 | } | |
87 | ||
88 | void | |
89 | derived_probe::printsig_nested (ostream& o) const | |
90 | { | |
91 | // We'd like to enclose the probe derivation chain in a /* */ | |
92 | // comment delimiter. But just printing /* base->printsig() */ is | |
93 | // not enough, since base might itself be a derived_probe. So we, | |
94 | // er, "cleverly" encode our nesting state as a formatting flag for | |
95 | // the ostream. | |
96 | ios::fmtflags f = o.flags (ios::internal); | |
97 | if (f & ios::internal) | |
98 | { | |
99 | // already nested | |
100 | o << " <- "; | |
101 | base->printsig (o); | |
102 | } | |
103 | else | |
104 | { | |
105 | // outermost nesting | |
106 | o << " /* <- "; | |
107 | base->printsig (o); | |
108 | o << " */"; | |
109 | } | |
110 | // restore flags | |
111 | (void) o.flags (f); | |
112 | } | |
113 | ||
114 | ||
c3a3c0c9 | 115 | void |
d885563b | 116 | derived_probe::collect_derivation_chain (std::vector<probe*> &probes_list) const |
c3a3c0c9 | 117 | { |
d885563b | 118 | probes_list.push_back(const_cast<derived_probe*>(this)); |
c3a3c0c9 WC |
119 | base->collect_derivation_chain(probes_list); |
120 | } | |
121 | ||
122 | ||
f1b9a51a | 123 | void |
d885563b | 124 | derived_probe::collect_derivation_pp_chain (std::vector<probe_point*> &pp_list) const |
f1b9a51a | 125 | { |
8159bf55 | 126 | pp_list.push_back(const_cast<probe_point*>(this->sole_location())); |
f1b9a51a JS |
127 | base->collect_derivation_pp_chain(pp_list); |
128 | } | |
129 | ||
130 | ||
26e63673 | 131 | string |
96c7f494 | 132 | derived_probe::derived_locations (bool firstFrom) |
26e63673 JS |
133 | { |
134 | ostringstream o; | |
135 | vector<probe_point*> reference_point; | |
136 | collect_derivation_pp_chain(reference_point); | |
d885563b FCE |
137 | if (reference_point.size() > 0) |
138 | for(unsigned i=1; i<reference_point.size(); ++i) | |
96c7f494 FCE |
139 | { |
140 | if (firstFrom || i>1) | |
141 | o << " from: "; | |
142 | o << reference_point[i]->str(false); // no ?,!,etc | |
143 | } | |
26e63673 JS |
144 | return o.str(); |
145 | } | |
146 | ||
147 | ||
b20febf3 | 148 | probe_point* |
b8da0ad1 | 149 | derived_probe::sole_location () const |
dc38c0ae | 150 | { |
4af765b2 | 151 | if (locations.size() == 0 || locations.size() > 1) |
dc09353a | 152 | throw SEMANTIC_ERROR (_N("derived_probe with no locations", |
2a89b023 | 153 | "derived_probe with too many locations", |
d885563b | 154 | locations.size()), this->tok); |
57148ee7 | 155 | else |
b20febf3 | 156 | return locations[0]; |
dc38c0ae DS |
157 | } |
158 | ||
159 | ||
c3df9bce JS |
160 | probe_point* |
161 | derived_probe::script_location () const | |
162 | { | |
d885563b | 163 | // This feeds function::pn() in the tapset, which is documented as the |
e2fee59d | 164 | // script-level probe point expression, *after wildcard expansion*. |
d885563b FCE |
165 | vector<probe_point*> chain; |
166 | collect_derivation_pp_chain (chain); | |
167 | ||
e2fee59d JL |
168 | // Go backwards until we hit the first well-formed probe point |
169 | for (int i=chain.size()-1; i>=0; i--) | |
170 | if (chain[i]->well_formed) | |
171 | return chain[i]; | |
d885563b | 172 | |
8159bf55 FCE |
173 | // If that didn't work, just fallback to -something-. |
174 | return sole_location(); | |
c3df9bce JS |
175 | } |
176 | ||
177 | ||
2865d17a | 178 | void |
42e38653 | 179 | derived_probe::emit_privilege_assertion (translator_output* o) |
2865d17a DB |
180 | { |
181 | // Emit code which will cause compilation to fail if it is compiled in | |
182 | // unprivileged mode. | |
f6be7c06 DB |
183 | o->newline() << "#if ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPDEV) && \\"; |
184 | o->newline() << " ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPSYS)"; | |
2865d17a DB |
185 | o->newline() << "#error Internal Error: Probe "; |
186 | probe::printsig (o->line()); | |
187 | o->line() << " generated in --unprivileged mode"; | |
188 | o->newline() << "#endif"; | |
189 | } | |
190 | ||
191 | ||
192 | void | |
193 | derived_probe::emit_process_owner_assertion (translator_output* o) | |
194 | { | |
195 | // Emit code which will abort should the current target not belong to the | |
196 | // user in unprivileged mode. | |
f6be7c06 DB |
197 | o->newline() << "#if ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPDEV) && \\"; |
198 | o->newline() << " ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPSYS)"; | |
2865d17a DB |
199 | o->newline(1) << "if (! is_myproc ()) {"; |
200 | o->newline(1) << "snprintf(c->error_buffer, sizeof(c->error_buffer),"; | |
201 | o->newline() << " \"Internal Error: Process %d does not belong to user %d in probe %s in --unprivileged mode\","; | |
202 | o->newline() << " current->tgid, _stp_uid, c->probe_point);"; | |
203 | o->newline() << "c->last_error = c->error_buffer;"; | |
991bd3ba JS |
204 | // NB: since this check occurs before probe locking, its exit should |
205 | // not be a "goto out", which would attempt unlocking. | |
206 | o->newline() << "return;"; | |
2865d17a DB |
207 | o->newline(-1) << "}"; |
208 | o->newline(-1) << "#endif"; | |
209 | } | |
210 | ||
8f6d8c2b DB |
211 | void |
212 | derived_probe::print_dupe_stamp_unprivileged(ostream& o) | |
213 | { | |
4af765b2 | 214 | o << _("unprivileged users: authorized") << endl; |
8f6d8c2b DB |
215 | } |
216 | ||
217 | void | |
218 | derived_probe::print_dupe_stamp_unprivileged_process_owner(ostream& o) | |
219 | { | |
4af765b2 | 220 | o << _("unprivileged users: authorized for process owner") << endl; |
8f6d8c2b | 221 | } |
47dd066d | 222 | |
20c6c071 | 223 | // ------------------------------------------------------------------------ |
98afd80e FCE |
224 | // Members of derived_probe_builder |
225 | ||
8eb6206c | 226 | void |
dabd71bb MW |
227 | derived_probe_builder::build_with_suffix(systemtap_session &, |
228 | probe *, | |
229 | probe_point *, | |
230 | literal_map_t const &, | |
231 | std::vector<derived_probe *> &, | |
8eb6206c | 232 | std::vector<probe_point::component *> |
dabd71bb | 233 | const &) { |
8eb6206c SM |
234 | // XXX perhaps build the probe if suffix is empty? |
235 | // if (suffix.empty()) { | |
236 | // build (sess, use, location, parameters, finished_results); | |
237 | // return; | |
238 | // } | |
dc09353a | 239 | throw SEMANTIC_ERROR (_("invalid suffix for probe")); |
8eb6206c SM |
240 | } |
241 | ||
98afd80e | 242 | bool |
45a63356 FCE |
243 | derived_probe_builder::get_param (literal_map_t const & params, |
244 | interned_string key, | |
245 | interned_string& value) | |
98afd80e | 246 | { |
45a63356 | 247 | literal_map_t::const_iterator i = params.find (key); |
98afd80e FCE |
248 | if (i == params.end()) |
249 | return false; | |
250 | literal_string * ls = dynamic_cast<literal_string *>(i->second); | |
251 | if (!ls) | |
252 | return false; | |
47d349b1 | 253 | value = ls->value; |
98afd80e FCE |
254 | return true; |
255 | } | |
256 | ||
20c6c071 | 257 | |
98afd80e | 258 | bool |
45a63356 FCE |
259 | derived_probe_builder::get_param (literal_map_t const & params, |
260 | interned_string key, | |
98afd80e FCE |
261 | int64_t& value) |
262 | { | |
45a63356 | 263 | literal_map_t::const_iterator i = params.find (key); |
98afd80e FCE |
264 | if (i == params.end()) |
265 | return false; | |
266 | if (i->second == NULL) | |
267 | return false; | |
268 | literal_number * ln = dynamic_cast<literal_number *>(i->second); | |
269 | if (!ln) | |
270 | return false; | |
271 | value = ln->value; | |
272 | return true; | |
273 | } | |
274 | ||
275 | ||
888af770 | 276 | bool |
45a63356 FCE |
277 | derived_probe_builder::has_null_param (literal_map_t const & params, |
278 | interned_string key) | |
888af770 | 279 | { |
45a63356 | 280 | literal_map_t::const_iterator i = params.find(key); |
888af770 FCE |
281 | return (i != params.end() && i->second == NULL); |
282 | } | |
283 | ||
5c6f9e92 | 284 | bool |
45a63356 FCE |
285 | derived_probe_builder::has_param (literal_map_t const & params, |
286 | interned_string key) | |
5c6f9e92 AJ |
287 | { |
288 | return (params.find(key) != params.end()); | |
289 | } | |
98afd80e FCE |
290 | |
291 | // ------------------------------------------------------------------------ | |
20c6c071 GH |
292 | // Members of match_key. |
293 | ||
45a63356 | 294 | match_key::match_key(interned_string n) |
47d349b1 | 295 | : name(n), |
57148ee7 | 296 | have_parameter(false), |
5d23847d | 297 | parameter_type(pe_unknown) |
20c6c071 GH |
298 | { |
299 | } | |
300 | ||
301 | match_key::match_key(probe_point::component const & c) | |
302 | : name(c.functor), | |
303 | have_parameter(c.arg != NULL), | |
5d23847d | 304 | parameter_type(c.arg ? c.arg->type : pe_unknown) |
20c6c071 GH |
305 | { |
306 | } | |
307 | ||
308 | match_key & | |
57148ee7 | 309 | match_key::with_number() |
20c6c071 GH |
310 | { |
311 | have_parameter = true; | |
5d23847d | 312 | parameter_type = pe_long; |
20c6c071 GH |
313 | return *this; |
314 | } | |
315 | ||
316 | match_key & | |
57148ee7 | 317 | match_key::with_string() |
20c6c071 GH |
318 | { |
319 | have_parameter = true; | |
5d23847d | 320 | parameter_type = pe_string; |
20c6c071 GH |
321 | return *this; |
322 | } | |
323 | ||
57148ee7 | 324 | string |
20c6c071 GH |
325 | match_key::str() const |
326 | { | |
47d349b1 | 327 | string n = name; |
20c6c071 GH |
328 | if (have_parameter) |
329 | switch (parameter_type) | |
330 | { | |
a3e980f9 FCE |
331 | case pe_string: return n + "(string)"; |
332 | case pe_long: return n + "(number)"; | |
333 | default: return n + "(...)"; | |
20c6c071 | 334 | } |
a3e980f9 | 335 | return n; |
20c6c071 GH |
336 | } |
337 | ||
57148ee7 | 338 | bool |
20c6c071 GH |
339 | match_key::operator<(match_key const & other) const |
340 | { | |
341 | return ((name < other.name) | |
57148ee7 FCE |
342 | |
343 | || (name == other.name | |
20c6c071 | 344 | && have_parameter < other.have_parameter) |
57148ee7 FCE |
345 | |
346 | || (name == other.name | |
347 | && have_parameter == other.have_parameter | |
20c6c071 GH |
348 | && parameter_type < other.parameter_type)); |
349 | } | |
2b066ec1 | 350 | |
c0c7b466 FCE |
351 | |
352 | // NB: these are only used in the probe point name components, where | |
353 | // only "*" is permitted. | |
354 | // | |
355 | // Within module("bar"), function("foo"), process("baz") strings, real | |
356 | // wildcards are permitted too. See also util.h:contains_glob_chars | |
357 | ||
a477f3f1 | 358 | static bool |
47d349b1 | 359 | isglob(interned_string str) |
a477f3f1 DS |
360 | { |
361 | return(str.find('*') != str.npos); | |
362 | } | |
363 | ||
122b4fcd | 364 | static bool |
47d349b1 | 365 | isdoubleglob(interned_string str) |
122b4fcd JS |
366 | { |
367 | return(str.find("**") != str.npos); | |
368 | } | |
369 | ||
a477f3f1 DS |
370 | bool |
371 | match_key::globmatch(match_key const & other) const | |
372 | { | |
7371cd19 JS |
373 | const string & name_str = name; |
374 | const string & other_str = other.name; | |
a477f3f1 | 375 | |
7371cd19 | 376 | return ((fnmatch(name_str.c_str(), other_str.c_str(), FNM_NOESCAPE) == 0) |
57148ee7 | 377 | && have_parameter == other.have_parameter |
a477f3f1 DS |
378 | && parameter_type == other.parameter_type); |
379 | } | |
380 | ||
2b066ec1 | 381 | // ------------------------------------------------------------------------ |
20c6c071 GH |
382 | // Members of match_node |
383 | // ------------------------------------------------------------------------ | |
384 | ||
27dc09b1 | 385 | match_node::match_node() : |
f6be7c06 | 386 | privilege(privilege_t (pr_stapdev | pr_stapsys)) |
d4935c2f | 387 | { |
d4935c2f | 388 | } |
20c6c071 GH |
389 | |
390 | match_node * | |
57148ee7 | 391 | match_node::bind(match_key const & k) |
20c6c071 | 392 | { |
b4ceace2 | 393 | if (k.name == "*") |
dc09353a | 394 | throw SEMANTIC_ERROR(_("invalid use of wildcard probe point component")); |
b4ceace2 | 395 | |
20c6c071 GH |
396 | map<match_key, match_node *>::const_iterator i = sub.find(k); |
397 | if (i != sub.end()) | |
398 | return i->second; | |
399 | match_node * n = new match_node(); | |
400 | sub.insert(make_pair(k, n)); | |
401 | return n; | |
402 | } | |
403 | ||
57148ee7 | 404 | void |
20c6c071 GH |
405 | match_node::bind(derived_probe_builder * e) |
406 | { | |
2531fc1e | 407 | ends.push_back (e); |
20c6c071 GH |
408 | } |
409 | ||
57148ee7 | 410 | match_node * |
45a63356 | 411 | match_node::bind(interned_string k) |
20c6c071 GH |
412 | { |
413 | return bind(match_key(k)); | |
414 | } | |
415 | ||
416 | match_node * | |
417 | match_node::bind_str(string const & k) | |
418 | { | |
419 | return bind(match_key(k).with_string()); | |
420 | } | |
421 | ||
57148ee7 | 422 | match_node * |
20c6c071 GH |
423 | match_node::bind_num(string const & k) |
424 | { | |
425 | return bind(match_key(k).with_number()); | |
426 | } | |
427 | ||
27dc09b1 | 428 | match_node * |
42e38653 | 429 | match_node::bind_privilege(privilege_t p) |
27dc09b1 | 430 | { |
42e38653 | 431 | privilege = p; |
27dc09b1 DB |
432 | return this; |
433 | } | |
434 | ||
b4ceace2 FCE |
435 | void |
436 | match_node::find_and_build (systemtap_session& s, | |
437 | probe* p, probe_point *loc, unsigned pos, | |
438 | vector<derived_probe *>& results) | |
20c6c071 | 439 | { |
b4ceace2 | 440 | assert (pos <= loc->components.size()); |
57148ee7 | 441 | if (pos == loc->components.size()) // matched all probe point components so far |
20c6c071 | 442 | { |
2531fc1e | 443 | if (ends.empty()) |
b4ceace2 FCE |
444 | { |
445 | string alternatives; | |
446 | for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++) | |
447 | alternatives += string(" ") + i->first.str(); | |
448 | ||
dc09353a | 449 | throw SEMANTIC_ERROR (_F("probe point truncated (follow: %s)", |
8eb6206c | 450 | alternatives.c_str()), |
4af765b2 | 451 | loc->components.back()->tok); |
b4ceace2 FCE |
452 | } |
453 | ||
f66bb29a | 454 | if (! pr_contains (privilege, s.privilege)) |
27dc09b1 | 455 | { |
dc09353a | 456 | throw SEMANTIC_ERROR (_F("probe point is not allowed for --privilege=%s", |
f66bb29a | 457 | pr_name (s.privilege)), |
4af765b2 | 458 | loc->components.back()->tok); |
27dc09b1 DB |
459 | } |
460 | ||
45a63356 | 461 | literal_map_t param_map; |
b4ceace2 | 462 | for (unsigned i=0; i<pos; i++) |
47d349b1 | 463 | param_map[loc->components[i]->functor] = loc->components[i]->arg; |
b4ceace2 FCE |
464 | // maybe 0 |
465 | ||
2531fc1e FCE |
466 | // Iterate over all bound builders |
467 | for (unsigned k=0; k<ends.size(); k++) | |
468 | { | |
469 | derived_probe_builder *b = ends[k]; | |
470 | b->build (s, p, loc, param_map, results); | |
471 | } | |
20c6c071 | 472 | } |
122b4fcd JS |
473 | else if (isdoubleglob(loc->components[pos]->functor)) // ** wildcard? |
474 | { | |
475 | unsigned int num_results = results.size(); | |
476 | ||
477 | // When faced with "foo**bar", we try "foo*bar" and "foo*.**bar" | |
478 | ||
479 | const probe_point::component *comp = loc->components[pos]; | |
47d349b1 | 480 | string functor = comp->functor; |
122b4fcd JS |
481 | size_t glob_start = functor.find("**"); |
482 | size_t glob_end = functor.find_first_not_of('*', glob_start); | |
a3e980f9 FCE |
483 | string prefix = functor.substr(0, glob_start); |
484 | string suffix = ((glob_end != string::npos) ? | |
485 | functor.substr(glob_end) : ""); | |
122b4fcd JS |
486 | |
487 | // Synthesize "foo*bar" | |
488 | probe_point *simple_pp = new probe_point(*loc); | |
489 | probe_point::component *simple_comp = new probe_point::component(*comp); | |
47d349b1 | 490 | simple_comp->functor = prefix + "*" + suffix; |
d2eaa03b | 491 | simple_comp->from_glob = true; |
122b4fcd JS |
492 | simple_pp->components[pos] = simple_comp; |
493 | try | |
494 | { | |
495 | find_and_build (s, p, simple_pp, pos, results); | |
496 | } | |
497 | catch (const semantic_error& e) | |
498 | { | |
601db063 JL |
499 | // Ignore semantic_errors. |
500 | } | |
501 | ||
502 | // Cleanup if we didn't find anything | |
503 | if (results.size() == num_results) | |
504 | { | |
122b4fcd JS |
505 | delete simple_pp; |
506 | delete simple_comp; | |
507 | } | |
508 | ||
601db063 JL |
509 | num_results = results.size(); |
510 | ||
122b4fcd JS |
511 | // Synthesize "foo*.**bar" |
512 | // NB: any component arg should attach to the latter part only | |
513 | probe_point *expanded_pp = new probe_point(*loc); | |
514 | probe_point::component *expanded_comp_pre = new probe_point::component(*comp); | |
47d349b1 | 515 | expanded_comp_pre->functor = prefix + "*"; |
d2eaa03b | 516 | expanded_comp_pre->from_glob = true; |
122b4fcd JS |
517 | expanded_comp_pre->arg = NULL; |
518 | probe_point::component *expanded_comp_post = new probe_point::component(*comp); | |
47d349b1 | 519 | expanded_comp_post->functor = string("**") + suffix; |
122b4fcd JS |
520 | expanded_pp->components[pos] = expanded_comp_pre; |
521 | expanded_pp->components.insert(expanded_pp->components.begin() + pos + 1, | |
522 | expanded_comp_post); | |
523 | try | |
524 | { | |
525 | find_and_build (s, p, expanded_pp, pos, results); | |
526 | } | |
527 | catch (const semantic_error& e) | |
528 | { | |
601db063 JL |
529 | // Ignore semantic_errors. |
530 | } | |
531 | ||
532 | // Cleanup if we didn't find anything | |
533 | if (results.size() == num_results) | |
534 | { | |
122b4fcd JS |
535 | delete expanded_pp; |
536 | delete expanded_comp_pre; | |
537 | delete expanded_comp_post; | |
538 | } | |
539 | ||
8eb6206c SM |
540 | // Try suffix expansion only if no matches found: |
541 | if (num_results == results.size()) | |
7f557fa7 | 542 | this->try_suffix_expansion (s, p, loc, pos, results); |
8eb6206c | 543 | |
122b4fcd JS |
544 | if (! loc->optional && num_results == results.size()) |
545 | { | |
546 | // We didn't find any wildcard matches (since the size of | |
547 | // the result vector didn't change). Throw an error. | |
cff6336b | 548 | string sugs = suggest_functors(s, functor); |
5bcb7b4e JL |
549 | throw SEMANTIC_ERROR (_F("probe point mismatch: didn't find any wildcard matches%s", |
550 | sugs.empty() ? "" : (" (similar: " + sugs + ")").c_str()), | |
551 | comp->tok); | |
122b4fcd JS |
552 | } |
553 | } | |
a477f3f1 | 554 | else if (isglob(loc->components[pos]->functor)) // wildcard? |
20c6c071 | 555 | { |
a477f3f1 DS |
556 | match_key match (* loc->components[pos]); |
557 | ||
828c3ed5 DS |
558 | // Call find_and_build for each possible match. Ignore errors - |
559 | // unless we don't find any match. | |
560 | unsigned int num_results = results.size(); | |
b4ceace2 FCE |
561 | for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++) |
562 | { | |
a477f3f1 | 563 | const match_key& subkey = i->first; |
828c3ed5 | 564 | match_node* subnode = i->second; |
a477f3f1 | 565 | |
e19ebcf7 | 566 | assert_no_interrupts(); |
49abf162 | 567 | |
a477f3f1 | 568 | if (match.globmatch(subkey)) |
828c3ed5 | 569 | { |
ddfc759e | 570 | if (s.verbose > 2) |
47d349b1 | 571 | clog << _F("wildcard '%s' matched '%s'", |
7371cd19 JS |
572 | loc->components[pos]->functor.to_string().c_str(), |
573 | subkey.name.to_string().c_str()) << endl; | |
a3e980f9 | 574 | |
ddfc759e DS |
575 | // When we have a wildcard, we need to create a copy of |
576 | // the probe point. Then we'll create a copy of the | |
577 | // wildcard component, and substitute the non-wildcard | |
578 | // functor. | |
579 | probe_point *non_wildcard_pp = new probe_point(*loc); | |
580 | probe_point::component *non_wildcard_component | |
581 | = new probe_point::component(*loc->components[pos]); | |
582 | non_wildcard_component->functor = subkey.name; | |
d2eaa03b | 583 | non_wildcard_component->from_glob = true; |
ddfc759e DS |
584 | non_wildcard_pp->components[pos] = non_wildcard_component; |
585 | ||
5d23847d FCE |
586 | // NB: probe conditions are not attached at the wildcard |
587 | // (component/functor) level, but at the overall | |
588 | // probe_point level. | |
589 | ||
601db063 JL |
590 | unsigned int inner_results = results.size(); |
591 | ||
ddfc759e | 592 | // recurse (with the non-wildcard probe point) |
a477f3f1 DS |
593 | try |
594 | { | |
ddfc759e DS |
595 | subnode->find_and_build (s, p, non_wildcard_pp, pos+1, |
596 | results); | |
a477f3f1 DS |
597 | } |
598 | catch (const semantic_error& e) | |
599 | { | |
600 | // Ignore semantic_errors while expanding wildcards. | |
601 | // If we get done and nothing was expanded, the code | |
602 | // following the loop will complain. | |
601db063 | 603 | } |
ddfc759e | 604 | |
601db063 JL |
605 | if (results.size() == inner_results) |
606 | { | |
ddfc759e DS |
607 | // If this wildcard didn't match, cleanup. |
608 | delete non_wildcard_pp; | |
609 | delete non_wildcard_component; | |
601db063 | 610 | } |
828c3ed5 | 611 | } |
a477f3f1 | 612 | } |
8eb6206c SM |
613 | |
614 | // Try suffix expansion only if no matches found: | |
615 | if (num_results == results.size()) | |
7f557fa7 | 616 | this->try_suffix_expansion (s, p, loc, pos, results); |
8eb6206c | 617 | |
cedd10f4 | 618 | if (! loc->optional && num_results == results.size()) |
828c3ed5 DS |
619 | { |
620 | // We didn't find any wildcard matches (since the size of | |
621 | // the result vector didn't change). Throw an error. | |
47d349b1 | 622 | string sugs = suggest_functors(s, loc->components[pos]->functor); |
5bcb7b4e JL |
623 | throw SEMANTIC_ERROR (_F("probe point mismatch: didn't find any wildcard matches%s", |
624 | sugs.empty() ? "" : (" (similar: " + sugs + ")").c_str()), | |
625 | loc->components[pos]->tok); | |
828c3ed5 | 626 | } |
b4ceace2 | 627 | } |
57148ee7 | 628 | else |
20c6c071 | 629 | { |
b4ceace2 FCE |
630 | match_key match (* loc->components[pos]); |
631 | sub_map_iterator_t i = sub.find (match); | |
8eb6206c SM |
632 | |
633 | if (i != sub.end()) // match found | |
b4ceace2 | 634 | { |
8eb6206c SM |
635 | match_node* subnode = i->second; |
636 | // recurse | |
637 | subnode->find_and_build (s, p, loc, pos+1, results); | |
638 | return; | |
639 | } | |
640 | ||
641 | unsigned int num_results = results.size(); | |
7f557fa7 | 642 | this->try_suffix_expansion (s, p, loc, pos, results); |
601db063 | 643 | |
8eb6206c SM |
644 | // XXX: how to correctly report alternatives + position numbers |
645 | // for alias suffixes? file a separate PR to address the issue | |
646 | if (! loc->optional && num_results == results.size()) | |
647 | { | |
648 | // We didn't find any alias suffixes (since the size of the | |
649 | // result vector didn't change). Throw an error. | |
47d349b1 | 650 | string sugs = suggest_functors(s, loc->components[pos]->functor); |
5bcb7b4e JL |
651 | throw SEMANTIC_ERROR (_F("probe point mismatch%s", |
652 | sugs.empty() ? "" : (" (similar: " + sugs + ")").c_str()), | |
653 | loc->components[pos]->tok); | |
b4ceace2 | 654 | } |
8eb6206c SM |
655 | } |
656 | } | |
657 | ||
5bcb7b4e | 658 | string |
cff6336b | 659 | match_node::suggest_functors(systemtap_session& s, string functor) |
5bcb7b4e JL |
660 | { |
661 | // only use prefix if globby (and prefix is non-empty) | |
662 | size_t glob = functor.find('*'); | |
663 | if (glob != string::npos && glob != 0) | |
664 | functor.erase(glob); | |
665 | if (functor.empty()) | |
666 | return ""; | |
667 | ||
cff6336b DS |
668 | // PR18577: There isn't any point in generating a suggestion list if |
669 | // we're not going to display it. | |
670 | if ((s.dump_mode == systemtap_session::dump_matched_probes | |
671 | || s.dump_mode == systemtap_session::dump_matched_probes_vars) | |
672 | && s.verbose < 2) | |
673 | return ""; | |
674 | ||
5bcb7b4e JL |
675 | set<string> functors; |
676 | for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++) | |
677 | { | |
678 | string ftor = i->first.str(); | |
679 | if (ftor.find('(') != string::npos) // trim any parameter | |
680 | ftor.erase(ftor.find('(')); | |
681 | functors.insert(ftor); | |
682 | } | |
683 | return levenshtein_suggest(functor, functors, 5); // print top 5 | |
684 | } | |
b4ceace2 | 685 | |
8eb6206c SM |
686 | void |
687 | match_node::try_suffix_expansion (systemtap_session& s, | |
688 | probe *p, probe_point *loc, unsigned pos, | |
689 | vector<derived_probe *>& results) | |
690 | { | |
691 | // PR12210: match alias suffixes. If the components thus far | |
692 | // have been matched, but there is an additional unknown | |
693 | // suffix, we have a potential alias suffix on our hands. We | |
694 | // need to expand the preceding components as probe aliases, | |
695 | // reattach the suffix, and re-run derive_probes() on the | |
696 | // resulting expansion. This is done by the routine | |
697 | // build_with_suffix(). | |
698 | ||
699 | if (strverscmp(s.compatible.c_str(), "2.0") >= 0) | |
700 | { | |
701 | // XXX: technically, param_map isn't used here. So don't | |
702 | // bother actually assembling it unless some | |
703 | // derived_probe_builder appears that actually takes | |
704 | // suffixes *and* consults parameters (currently no such | |
705 | // builders exist). | |
45a63356 | 706 | literal_map_t param_map; |
8eb6206c SM |
707 | // for (unsigned i=0; i<pos; i++) |
708 | // param_map[loc->components[i]->functor] = loc->components[i]->arg; | |
709 | // maybe 0 | |
710 | ||
711 | vector<probe_point::component *> suffix (loc->components.begin()+pos, | |
712 | loc->components.end()); | |
713 | ||
714 | // Multiple derived_probe_builders may be bound at a | |
715 | // match_node due to the possibility of multiply defined | |
716 | // aliases. | |
717 | for (unsigned k=0; k < ends.size(); k++) | |
718 | { | |
719 | derived_probe_builder *b = ends[k]; | |
7f557fa7 | 720 | try |
8eb6206c SM |
721 | { |
722 | b->build_with_suffix (s, p, loc, param_map, results, suffix); | |
7f557fa7 | 723 | } |
8eb6206c SM |
724 | catch (const recursive_expansion_error &e) |
725 | { | |
726 | // Re-throw: | |
e758508b | 727 | throw semantic_error(e); |
8eb6206c SM |
728 | } |
729 | catch (const semantic_error &e) | |
730 | { | |
731 | // Adjust source coordinate and re-throw: | |
732 | if (! loc->optional) | |
dc09353a | 733 | throw semantic_error(e.errsrc, e.what(), loc->components[pos]->tok); |
8eb6206c SM |
734 | } |
735 | } | |
20c6c071 GH |
736 | } |
737 | } | |
738 | ||
b4ceace2 | 739 | |
aa30ccd3 FCE |
740 | void |
741 | match_node::build_no_more (systemtap_session& s) | |
742 | { | |
743 | for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++) | |
744 | i->second->build_no_more (s); | |
2531fc1e FCE |
745 | for (unsigned k=0; k<ends.size(); k++) |
746 | { | |
747 | derived_probe_builder *b = ends[k]; | |
748 | b->build_no_more (s); | |
749 | } | |
aa30ccd3 FCE |
750 | } |
751 | ||
b82d77b4 DB |
752 | void |
753 | match_node::dump (systemtap_session &s, const string &name) | |
754 | { | |
755 | // Dump this node, if it is complete. | |
756 | for (unsigned k=0; k<ends.size(); k++) | |
757 | { | |
758 | // Don't print aliases at all (for now) until we can figure out how to determine whether | |
759 | // the probes they resolve to are ok in unprivileged mode. | |
760 | if (ends[k]->is_alias ()) | |
761 | continue; | |
762 | ||
763 | // In unprivileged mode, don't show the probes which are not allowed for unprivileged | |
764 | // users. | |
f66bb29a | 765 | if (pr_contains (privilege, s.privilege)) |
b82d77b4 DB |
766 | { |
767 | cout << name << endl; | |
768 | break; // we need only print one instance. | |
769 | } | |
770 | } | |
771 | ||
772 | // Recursively dump the children of this node | |
773 | string dot; | |
774 | if (! name.empty ()) | |
775 | dot = "."; | |
776 | for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++) | |
777 | { | |
778 | i->second->dump (s, name + dot + i->first.str()); | |
779 | } | |
780 | } | |
781 | ||
aa30ccd3 | 782 | |
20c6c071 GH |
783 | // ------------------------------------------------------------------------ |
784 | // Alias probes | |
785 | // ------------------------------------------------------------------------ | |
786 | ||
c1d5f3f6 FCE |
787 | struct alias_derived_probe: public derived_probe |
788 | { | |
8eb6206c SM |
789 | alias_derived_probe (probe* base, probe_point *l, const probe_alias *a, |
790 | const vector<probe_point::component *> *suffix = 0); | |
1e2efea5 | 791 | ~alias_derived_probe(); |
c1d5f3f6 | 792 | |
dc09353a | 793 | void upchuck () { throw SEMANTIC_ERROR (_("inappropriate"), this->tok); } |
b20febf3 FCE |
794 | |
795 | // Alias probes are immediately expanded to other derived_probe | |
796 | // types, and are not themselves emitted or listed in | |
797 | // systemtap_session.probes | |
dc38c0ae | 798 | |
78f6bba6 | 799 | void join_group (systemtap_session&) { upchuck (); } |
2c5a19c6 DB |
800 | |
801 | virtual const probe_alias *get_alias () const { return alias; } | |
8eb6206c | 802 | virtual probe_point *get_alias_loc () const { return alias_loc; } |
2a89b023 | 803 | virtual probe_point *sole_location () const; |
2c5a19c6 DB |
804 | |
805 | private: | |
806 | const probe_alias *alias; // Used to check for recursion | |
8eb6206c | 807 | probe_point *alias_loc; // Hack to recover full probe name |
c1d5f3f6 FCE |
808 | }; |
809 | ||
8eb6206c SM |
810 | |
811 | alias_derived_probe::alias_derived_probe(probe *base, probe_point *l, | |
812 | const probe_alias *a, | |
813 | const vector<probe_point::component *> | |
814 | *suffix): | |
815 | derived_probe (base, l), alias(a) | |
816 | { | |
817 | // XXX pretty nasty -- this was cribbed from printscript() in main.cxx | |
818 | assert (alias->alias_names.size() >= 1); | |
819 | alias_loc = new probe_point(*alias->alias_names[0]); // XXX: [0] is arbitrary; it would make just as much sense to collect all of the names | |
da631035 JL |
820 | alias_loc->well_formed = true; |
821 | vector<probe_point::component*>::const_iterator it; | |
822 | for (it = suffix->begin(); it != suffix->end(); ++it) | |
823 | { | |
824 | alias_loc->components.push_back(*it); | |
825 | if (isglob((*it)->functor)) | |
826 | alias_loc->well_formed = false; // needs further derivation | |
827 | } | |
8eb6206c SM |
828 | } |
829 | ||
1e2efea5 SM |
830 | alias_derived_probe::~alias_derived_probe () |
831 | { | |
832 | delete alias_loc; | |
833 | } | |
834 | ||
8eb6206c | 835 | |
2a89b023 FCE |
836 | probe_point* |
837 | alias_derived_probe::sole_location () const | |
838 | { | |
839 | return const_cast<probe_point*>(alias_loc); | |
840 | } | |
841 | ||
842 | ||
e2012a7a DB |
843 | void |
844 | alias_expansion_builder::build(systemtap_session & sess, | |
845 | probe * use, | |
846 | probe_point * location, | |
45a63356 | 847 | literal_map_t const & parameters, |
e2012a7a | 848 | vector<derived_probe *> & finished_results) |
8eb6206c SM |
849 | { |
850 | vector<probe_point::component *> empty_suffix; | |
851 | build_with_suffix (sess, use, location, parameters, | |
852 | finished_results, empty_suffix); | |
853 | } | |
854 | ||
855 | void | |
856 | alias_expansion_builder::build_with_suffix(systemtap_session & sess, | |
857 | probe * use, | |
858 | probe_point * location, | |
45a63356 | 859 | literal_map_t const &, |
8eb6206c SM |
860 | vector<derived_probe *> |
861 | & finished_results, | |
862 | vector<probe_point::component *> | |
863 | const & suffix) | |
20c6c071 | 864 | { |
e2012a7a DB |
865 | // Don't build the alias expansion if infinite recursion is detected. |
866 | if (checkForRecursiveExpansion (use)) { | |
867 | stringstream msg; | |
7f557fa7 | 868 | msg << _F("recursive loop in alias expansion of %s at %s", |
4af765b2 | 869 | lex_cast(*location).c_str(), lex_cast(location->components.front()->tok->location).c_str()); |
8eb6206c SM |
870 | // semantic_errors thrown here might be ignored, so we need a special class: |
871 | throw recursive_expansion_error (msg.str()); | |
872 | // XXX The point of throwing this custom error is to suppress a | |
873 | // cascade of "probe mismatch" messages that appear in addition to | |
874 | // the error. The current approach suppresses most of the error | |
875 | // cascade, but leaves one spurious error; in any case, the way | |
876 | // this particular error is reported could be improved. | |
e2012a7a | 877 | } |
57148ee7 | 878 | |
e2012a7a DB |
879 | // We're going to build a new probe and wrap it up in an |
880 | // alias_expansion_probe so that the expansion loop recognizes it as | |
881 | // such and re-expands its expansion. | |
20c6c071 | 882 | |
8eb6206c | 883 | alias_derived_probe * n = new alias_derived_probe (use, location /* soon overwritten */, this->alias, &suffix); |
e2012a7a | 884 | n->body = new block(); |
5d23847d | 885 | |
8eb6206c SM |
886 | // The new probe gets a deep copy of the location list of the alias |
887 | // (with incoming condition joined) plus the suffix (if any), | |
e2012a7a DB |
888 | n->locations.clear(); |
889 | for (unsigned i=0; i<alias->locations.size(); i++) | |
890 | { | |
891 | probe_point *pp = new probe_point(*alias->locations[i]); | |
8eb6206c | 892 | pp->components.insert(pp->components.end(), suffix.begin(), suffix.end()); |
e2012a7a DB |
893 | pp->condition = add_condition (pp->condition, location->condition); |
894 | n->locations.push_back(pp); | |
895 | } | |
20c6c071 | 896 | |
e2012a7a DB |
897 | // the token location of the alias, |
898 | n->tok = location->components.front()->tok; | |
5227f1ea | 899 | |
e2012a7a DB |
900 | // and statements representing the concatenation of the alias' |
901 | // body with the use's. | |
902 | // | |
903 | // NB: locals are *not* copied forward, from either alias or | |
904 | // use. The expansion should have its locals re-inferred since | |
905 | // there's concatenated code here and we only want one vardecl per | |
906 | // resulting variable. | |
57148ee7 | 907 | |
e2012a7a DB |
908 | if (alias->epilogue_style) |
909 | n->body = new block (use->body, alias->body); | |
910 | else | |
911 | n->body = new block (alias->body, use->body); | |
a3b4f52c | 912 | |
e2012a7a | 913 | unsigned old_num_results = finished_results.size(); |
8eb6206c SM |
914 | // If expanding for an alias suffix, be sure to pass on any errors |
915 | // to the caller instead of printing them in derive_probes(): | |
916 | derive_probes (sess, n, finished_results, location->optional, !suffix.empty()); | |
2c5a19c6 | 917 | |
e2012a7a DB |
918 | // Check whether we resolved something. If so, put the |
919 | // whole library into the queue if not already there. | |
920 | if (finished_results.size() > old_num_results) | |
921 | { | |
922 | stapfile *f = alias->tok->location.file; | |
923 | if (find (sess.files.begin(), sess.files.end(), f) | |
924 | == sess.files.end()) | |
925 | sess.files.push_back (f); | |
2c5a19c6 | 926 | } |
e2012a7a DB |
927 | } |
928 | ||
929 | bool | |
930 | alias_expansion_builder::checkForRecursiveExpansion (probe *use) | |
931 | { | |
932 | // Collect the derivation chain of this probe. | |
933 | vector<probe*>derivations; | |
934 | use->collect_derivation_chain (derivations); | |
935 | ||
936 | // Check all probe points in the alias expansion against the currently-being-expanded probe point | |
937 | // of each of the probes in the derivation chain, looking for a match. This | |
938 | // indicates infinite recursion. | |
939 | // The first element of the derivation chain will be the derived_probe representing 'use', so | |
940 | // start the search with the second element. | |
941 | assert (derivations.size() > 0); | |
942 | assert (derivations[0] == use); | |
943 | for (unsigned d = 1; d < derivations.size(); ++d) { | |
944 | if (use->get_alias() == derivations[d]->get_alias()) | |
945 | return true; // recursion detected | |
2c5a19c6 | 946 | } |
e2012a7a DB |
947 | return false; |
948 | } | |
20c6c071 GH |
949 | |
950 | ||
951 | // ------------------------------------------------------------------------ | |
952 | // Pattern matching | |
953 | // ------------------------------------------------------------------------ | |
954 | ||
5227f1ea GH |
955 | static unsigned max_recursion = 100; |
956 | ||
57148ee7 | 957 | struct |
5227f1ea GH |
958 | recursion_guard |
959 | { | |
960 | unsigned & i; | |
961 | recursion_guard(unsigned & i) : i(i) | |
962 | { | |
963 | if (i > max_recursion) | |
dc09353a | 964 | throw SEMANTIC_ERROR(_("recursion limit reached")); |
5227f1ea GH |
965 | ++i; |
966 | } | |
57148ee7 | 967 | ~recursion_guard() |
5227f1ea GH |
968 | { |
969 | --i; | |
970 | } | |
971 | }; | |
972 | ||
20c6c071 GH |
973 | // The match-and-expand loop. |
974 | void | |
b4ceace2 FCE |
975 | derive_probes (systemtap_session& s, |
976 | probe *p, vector<derived_probe*>& dps, | |
8eb6206c SM |
977 | bool optional, |
978 | bool rethrow_errors) | |
20c6c071 | 979 | { |
168e2ef5 JL |
980 | // We need a static to track whether the current probe is optional so that |
981 | // even if we recurse into derive_probes with optional = false, errors will | |
982 | // still be ignored. The undo_parent_optional bool ensures we reset the | |
983 | // static at the same level we had it set. | |
984 | static bool parent_optional = false; | |
985 | bool undo_parent_optional = false; | |
986 | ||
987 | if (optional && !parent_optional) | |
988 | { | |
989 | parent_optional = true; | |
990 | undo_parent_optional = true; | |
991 | } | |
992 | ||
4f31fb82 JL |
993 | vector <semantic_error> optional_errs; |
994 | ||
20c6c071 GH |
995 | for (unsigned i = 0; i < p->locations.size(); ++i) |
996 | { | |
e19ebcf7 | 997 | assert_no_interrupts(); |
49abf162 | 998 | |
20c6c071 | 999 | probe_point *loc = p->locations[i]; |
a971b891 | 1000 | |
d885563b FCE |
1001 | if (s.verbose > 4) |
1002 | clog << "derive-probes " << *loc << endl; | |
1003 | ||
fe3d01fa FCE |
1004 | try |
1005 | { | |
fe3d01fa | 1006 | unsigned num_atbegin = dps.size(); |
d898100a | 1007 | |
74efda8d WH |
1008 | try |
1009 | { | |
1010 | s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation! | |
1011 | } | |
1012 | catch (const semantic_error& e) | |
1013 | { | |
168e2ef5 | 1014 | if (!loc->optional && !parent_optional) |
74efda8d WH |
1015 | throw semantic_error(e); |
1016 | else /* tolerate failure for optional probe */ | |
4f31fb82 JL |
1017 | { |
1018 | // remember err, we will print it (in catch block) if any | |
1019 | // non-optional loc fails to resolve | |
1020 | semantic_error err(ERR_SRC, _("while resolving probe point"), | |
1021 | loc->components[0]->tok, NULL, &e); | |
1022 | optional_errs.push_back(err); | |
1023 | continue; | |
1024 | } | |
74efda8d WH |
1025 | } |
1026 | ||
fe3d01fa | 1027 | unsigned num_atend = dps.size(); |
d898100a | 1028 | |
168e2ef5 | 1029 | if (! (loc->optional||parent_optional) && // something required, but |
cedd10f4 | 1030 | num_atbegin == num_atend) // nothing new derived! |
dc09353a | 1031 | throw SEMANTIC_ERROR (_("no match")); |
d898100a FCE |
1032 | |
1033 | if (loc->sufficient && (num_atend > num_atbegin)) | |
1034 | { | |
1035 | if (s.verbose > 1) | |
1036 | { | |
1037 | clog << "Probe point "; | |
1038 | p->locations[i]->print(clog); | |
1039 | clog << " sufficient, skipped"; | |
1040 | for (unsigned j = i+1; j < p->locations.size(); ++j) | |
1041 | { | |
1042 | clog << " "; | |
1043 | p->locations[j]->print(clog); | |
1044 | } | |
1045 | clog << endl; | |
1046 | } | |
1047 | break; // we need not try to derive for any other locations | |
1048 | } | |
fe3d01fa FCE |
1049 | } |
1050 | catch (const semantic_error& e) | |
1051 | { | |
8eb6206c SM |
1052 | // The rethrow_errors parameter lets the caller decide an |
1053 | // alternative to printing the error. This is necessary when | |
1054 | // calling derive_probes() recursively during expansion of | |
1055 | // an alias with suffix -- any message printed here would | |
1056 | // point to the alias declaration and not the invalid suffix | |
1057 | // usage, so the caller needs to catch the error themselves | |
1058 | // and print a more appropriate message. | |
1059 | if (rethrow_errors) | |
1060 | { | |
e758508b | 1061 | throw semantic_error(e); |
8eb6206c | 1062 | } |
bba368c5 JL |
1063 | // Only output in dump mode if -vv is supplied: |
1064 | else if (!s.dump_mode || (s.verbose > 1)) | |
68ac5d0e | 1065 | { |
4f31fb82 JL |
1066 | // print this one manually first because it's more important than |
1067 | // the optional errs | |
1068 | semantic_error err(ERR_SRC, _("while resolving probe point"), | |
1069 | loc->components[0]->tok, NULL, &e); | |
1070 | s.print_error(err); | |
1071 | ||
1072 | // print optional errs accumulated while visiting other probe points | |
1073 | for (vector<semantic_error>::const_iterator it = optional_errs.begin(); | |
1074 | it != optional_errs.end(); ++it) | |
1075 | { | |
1076 | s.print_error(*it); | |
1077 | } | |
68ac5d0e | 1078 | } |
fe3d01fa | 1079 | } |
20c6c071 | 1080 | } |
168e2ef5 JL |
1081 | |
1082 | if (undo_parent_optional) | |
1083 | parent_optional = false; | |
20c6c071 GH |
1084 | } |
1085 | ||
b4ceace2 FCE |
1086 | |
1087 | ||
20c6c071 | 1088 | // ------------------------------------------------------------------------ |
67c0a579 | 1089 | // |
d02548c0 | 1090 | // Indexable usage checks |
67c0a579 GH |
1091 | // |
1092 | ||
d02548c0 | 1093 | struct symbol_fetcher |
07c17d67 | 1094 | : public throwing_visitor |
67c0a579 | 1095 | { |
d02548c0 | 1096 | symbol *&sym; |
67c0a579 | 1097 | |
57148ee7 | 1098 | symbol_fetcher (symbol *&sym): sym(sym) |
67c0a579 GH |
1099 | {} |
1100 | ||
d02548c0 GH |
1101 | void visit_symbol (symbol* e) |
1102 | { | |
1103 | sym = e; | |
1104 | } | |
1105 | ||
1106 | void visit_arrayindex (arrayindex* e) | |
1107 | { | |
d15d767c | 1108 | e->base->visit (this); |
d02548c0 GH |
1109 | } |
1110 | ||
1111 | void throwone (const token* t) | |
1112 | { | |
bd70b999 | 1113 | throw SEMANTIC_ERROR (_("Expecting symbol or array index expression"), t); |
d02548c0 GH |
1114 | } |
1115 | }; | |
1116 | ||
07c17d67 | 1117 | symbol * |
d02548c0 GH |
1118 | get_symbol_within_expression (expression *e) |
1119 | { | |
1120 | symbol *sym = NULL; | |
1121 | symbol_fetcher fetcher(sym); | |
1122 | e->visit (&fetcher); | |
b0be9bdb | 1123 | return sym; // NB: may be null! |
d02548c0 GH |
1124 | } |
1125 | ||
1126 | static symbol * | |
1127 | get_symbol_within_indexable (indexable *ix) | |
1128 | { | |
1129 | symbol *array = NULL; | |
1130 | hist_op *hist = NULL; | |
1131 | classify_indexable(ix, array, hist); | |
1132 | if (array) | |
1133 | return array; | |
1134 | else | |
1135 | return get_symbol_within_expression (hist->stat); | |
1136 | } | |
1137 | ||
1138 | struct mutated_var_collector | |
07c17d67 | 1139 | : public traversing_visitor |
d02548c0 GH |
1140 | { |
1141 | set<vardecl *> * mutated_vars; | |
1142 | ||
57148ee7 | 1143 | mutated_var_collector (set<vardecl *> * mm) |
d02548c0 GH |
1144 | : mutated_vars (mm) |
1145 | {} | |
1146 | ||
1147 | void visit_assignment(assignment* e) | |
1148 | { | |
1149 | if (e->type == pe_stats && e->op == "<<<") | |
1150 | { | |
1151 | vardecl *vd = get_symbol_within_expression (e->left)->referent; | |
1152 | if (vd) | |
1153 | mutated_vars->insert (vd); | |
1154 | } | |
1bbeef03 | 1155 | traversing_visitor::visit_assignment(e); |
d02548c0 GH |
1156 | } |
1157 | ||
67c0a579 GH |
1158 | void visit_arrayindex (arrayindex *e) |
1159 | { | |
d02548c0 GH |
1160 | if (is_active_lvalue (e)) |
1161 | { | |
1162 | symbol *sym; | |
1163 | if (e->base->is_symbol (sym)) | |
1164 | mutated_vars->insert (sym->referent); | |
1165 | else | |
dc09353a | 1166 | throw SEMANTIC_ERROR(_("Assignment to read-only histogram bucket"), e->tok); |
d02548c0 | 1167 | } |
1bbeef03 | 1168 | traversing_visitor::visit_arrayindex (e); |
67c0a579 GH |
1169 | } |
1170 | }; | |
1171 | ||
1172 | ||
d02548c0 | 1173 | struct no_var_mutation_during_iteration_check |
07c17d67 | 1174 | : public traversing_visitor |
67c0a579 GH |
1175 | { |
1176 | systemtap_session & session; | |
d02548c0 GH |
1177 | map<functiondecl *,set<vardecl *> *> & function_mutates_vars; |
1178 | vector<vardecl *> vars_being_iterated; | |
57148ee7 FCE |
1179 | |
1180 | no_var_mutation_during_iteration_check | |
67c0a579 | 1181 | (systemtap_session & sess, |
d02548c0 GH |
1182 | map<functiondecl *,set<vardecl *> *> & fmv) |
1183 | : session(sess), function_mutates_vars (fmv) | |
67c0a579 GH |
1184 | {} |
1185 | ||
1186 | void visit_arrayindex (arrayindex *e) | |
1187 | { | |
d7f3e0c5 | 1188 | if (is_active_lvalue(e)) |
67c0a579 | 1189 | { |
d02548c0 GH |
1190 | vardecl *vd = get_symbol_within_indexable (e->base)->referent; |
1191 | if (vd) | |
67c0a579 | 1192 | { |
d02548c0 | 1193 | for (unsigned i = 0; i < vars_being_iterated.size(); ++i) |
67c0a579 | 1194 | { |
d02548c0 GH |
1195 | vardecl *v = vars_being_iterated[i]; |
1196 | if (v == vd) | |
1197 | { | |
4af765b2 | 1198 | string err = _F("variable '%s' modified during 'foreach' iteration", |
5eb6ecb1 | 1199 | v->unmangled_name.to_string().c_str()); |
dc09353a | 1200 | session.print_error (SEMANTIC_ERROR (err, e->tok)); |
d02548c0 | 1201 | } |
67c0a579 GH |
1202 | } |
1203 | } | |
1204 | } | |
1bbeef03 | 1205 | traversing_visitor::visit_arrayindex (e); |
67c0a579 GH |
1206 | } |
1207 | ||
1208 | void visit_functioncall (functioncall* e) | |
1209 | { | |
7b5b30a8 | 1210 | for (unsigned fd = 0; fd < e->referents.size(); fd++) |
67c0a579 | 1211 | { |
7b5b30a8 FL |
1212 | map<functiondecl *,set<vardecl *> *>::const_iterator i |
1213 | = function_mutates_vars.find (e->referents[fd]); | |
1214 | ||
1215 | if (i != function_mutates_vars.end()) | |
1216 | { | |
1217 | for (unsigned j = 0; j < vars_being_iterated.size(); ++j) | |
1218 | { | |
1219 | vardecl *m = vars_being_iterated[j]; | |
1220 | if (i->second->find (m) != i->second->end()) | |
1221 | { | |
1222 | string err = _F("function call modifies var '%s' during 'foreach' iteration", | |
1223 | m->unmangled_name.to_string().c_str()); | |
1224 | session.print_error (SEMANTIC_ERROR (err, e->tok)); | |
1225 | } | |
1226 | } | |
1227 | } | |
67c0a579 GH |
1228 | } |
1229 | ||
1bbeef03 | 1230 | traversing_visitor::visit_functioncall (e); |
67c0a579 GH |
1231 | } |
1232 | ||
1233 | void visit_foreach_loop(foreach_loop* s) | |
1234 | { | |
d02548c0 GH |
1235 | vardecl *vd = get_symbol_within_indexable (s->base)->referent; |
1236 | ||
1237 | if (vd) | |
1238 | vars_being_iterated.push_back (vd); | |
57148ee7 | 1239 | |
1bbeef03 | 1240 | traversing_visitor::visit_foreach_loop (s); |
d02548c0 GH |
1241 | |
1242 | if (vd) | |
1243 | vars_being_iterated.pop_back(); | |
67c0a579 GH |
1244 | } |
1245 | }; | |
20c6c071 | 1246 | |
2b066ec1 | 1247 | |
67c0a579 GH |
1248 | // ------------------------------------------------------------------------ |
1249 | ||
07c17d67 GH |
1250 | struct stat_decl_collector |
1251 | : public traversing_visitor | |
1252 | { | |
1253 | systemtap_session & session; | |
57148ee7 | 1254 | |
07c17d67 GH |
1255 | stat_decl_collector(systemtap_session & sess) |
1256 | : session(sess) | |
1257 | {} | |
1258 | ||
1259 | void visit_stat_op (stat_op* e) | |
1260 | { | |
1261 | symbol *sym = get_symbol_within_expression (e->stat); | |
1262 | if (session.stat_decls.find(sym->name) == session.stat_decls.end()) | |
1263 | session.stat_decls[sym->name] = statistic_decl(); | |
1264 | } | |
1265 | ||
1266 | void visit_assignment (assignment* e) | |
1267 | { | |
1268 | if (e->op == "<<<") | |
1269 | { | |
1270 | symbol *sym = get_symbol_within_expression (e->left); | |
1271 | if (session.stat_decls.find(sym->name) == session.stat_decls.end()) | |
1272 | session.stat_decls[sym->name] = statistic_decl(); | |
1273 | } | |
1274 | else | |
1275 | traversing_visitor::visit_assignment(e); | |
1276 | } | |
1277 | ||
1278 | void visit_hist_op (hist_op* e) | |
1279 | { | |
1280 | symbol *sym = get_symbol_within_expression (e->stat); | |
1281 | statistic_decl new_stat; | |
1282 | ||
1283 | if (e->htype == hist_linear) | |
1284 | { | |
1285 | new_stat.type = statistic_decl::linear; | |
1286 | assert (e->params.size() == 3); | |
1287 | new_stat.linear_low = e->params[0]; | |
1288 | new_stat.linear_high = e->params[1]; | |
1289 | new_stat.linear_step = e->params[2]; | |
1290 | } | |
1291 | else | |
1292 | { | |
1293 | assert (e->htype == hist_log); | |
1294 | new_stat.type = statistic_decl::logarithmic; | |
e38723d2 | 1295 | assert (e->params.size() == 0); |
07c17d67 GH |
1296 | } |
1297 | ||
47d349b1 | 1298 | map<interned_string, statistic_decl>::iterator i = session.stat_decls.find(sym->name); |
07c17d67 GH |
1299 | if (i == session.stat_decls.end()) |
1300 | session.stat_decls[sym->name] = new_stat; | |
1301 | else | |
1302 | { | |
1303 | statistic_decl & old_stat = i->second; | |
1304 | if (!(old_stat == new_stat)) | |
1305 | { | |
1306 | if (old_stat.type == statistic_decl::none) | |
1307 | i->second = new_stat; | |
1308 | else | |
1309 | { | |
1310 | // FIXME: Support multiple co-declared histogram types | |
7371cd19 JS |
1311 | semantic_error se(ERR_SRC, _F("multiple histogram types declared on '%s'", |
1312 | sym->name.to_string().c_str()), e->tok); | |
07c17d67 GH |
1313 | session.print_error (se); |
1314 | } | |
1315 | } | |
57148ee7 | 1316 | } |
07c17d67 GH |
1317 | } |
1318 | ||
1319 | }; | |
1320 | ||
1321 | static int | |
1322 | semantic_pass_stats (systemtap_session & sess) | |
1323 | { | |
1324 | stat_decl_collector sdc(sess); | |
1325 | ||
f76427a2 FCE |
1326 | for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++) |
1327 | it->second->body->visit (&sdc); | |
07c17d67 | 1328 | |
57148ee7 | 1329 | for (unsigned i = 0; i < sess.probes.size(); ++i) |
07c17d67 GH |
1330 | sess.probes[i]->body->visit (&sdc); |
1331 | ||
1332 | for (unsigned i = 0; i < sess.globals.size(); ++i) | |
1333 | { | |
1334 | vardecl *v = sess.globals[i]; | |
1335 | if (v->type == pe_stats) | |
1336 | { | |
57148ee7 | 1337 | |
07c17d67 GH |
1338 | if (sess.stat_decls.find(v->name) == sess.stat_decls.end()) |
1339 | { | |
7371cd19 | 1340 | semantic_error se(ERR_SRC, _F("unable to infer statistic parameters for global '%s'", |
5eb6ecb1 | 1341 | v->unmangled_name.to_string().c_str())); |
07c17d67 GH |
1342 | sess.print_error (se); |
1343 | } | |
1344 | } | |
1345 | } | |
57148ee7 | 1346 | |
7e41d3dc | 1347 | return sess.num_errors(); |
07c17d67 GH |
1348 | } |
1349 | ||
5d23847d FCE |
1350 | // ------------------------------------------------------------------------ |
1351 | ||
1352 | // Enforce variable-related invariants: no modification of | |
1353 | // a foreach()-iterated array. | |
1354 | static int | |
1355 | semantic_pass_vars (systemtap_session & sess) | |
1356 | { | |
57148ee7 | 1357 | |
5d23847d FCE |
1358 | map<functiondecl *, set<vardecl *> *> fmv; |
1359 | no_var_mutation_during_iteration_check chk(sess, fmv); | |
57148ee7 | 1360 | |
f76427a2 | 1361 | for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++) |
5d23847d | 1362 | { |
f76427a2 | 1363 | functiondecl * fn = it->second; |
5d23847d FCE |
1364 | if (fn->body) |
1365 | { | |
1366 | set<vardecl *> * m = new set<vardecl *>(); | |
1367 | mutated_var_collector mc (m); | |
1368 | fn->body->visit (&mc); | |
1369 | fmv[fn] = m; | |
1370 | } | |
1371 | } | |
1372 | ||
f76427a2 | 1373 | for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++) |
5d23847d | 1374 | { |
f76427a2 FCE |
1375 | functiondecl * fn = it->second; |
1376 | if (fn->body) fn->body->visit (&chk); | |
5d23847d FCE |
1377 | } |
1378 | ||
1379 | for (unsigned i = 0; i < sess.probes.size(); ++i) | |
1380 | { | |
1381 | if (sess.probes[i]->body) | |
1382 | sess.probes[i]->body->visit (&chk); | |
57148ee7 | 1383 | } |
5d23847d FCE |
1384 | |
1385 | return sess.num_errors(); | |
1386 | } | |
1387 | ||
1388 | ||
1389 | // ------------------------------------------------------------------------ | |
1390 | ||
1391 | // Rewrite probe condition expressions into probe bodies. Tricky and | |
1392 | // exciting business, this. This: | |
1393 | // | |
1394 | // probe foo if (g1 || g2) { ... } | |
1395 | // probe bar { ... g1 ++ ... } | |
1396 | // | |
1397 | // becomes: | |
1398 | // | |
5d23847d | 1399 | // probe foo { if (! (g1 || g2)) next; ... } |
57148ee7 | 1400 | // probe bar { ... g1 ++ ...; |
5d23847d FCE |
1401 | // if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %} |
1402 | // } | |
1403 | // | |
ecf50eda JL |
1404 | // In other words, we perform two transformations: |
1405 | // (1) Inline probe condition into its body. | |
1406 | // (2) For each probe that modifies a global var in use in any probe's | |
1407 | // condition, re-evaluate those probes' condition at the end of that | |
1408 | // probe's body. | |
1409 | // | |
1410 | // Here, we do all of (1), and half of (2): we simply collect the dependency | |
1411 | // info between probes, which the translator will use to emit the affected | |
1412 | // probes' condition re-evaluation. The translator will also ensure that the | |
1413 | // conditions are evaluated using the globals' starting values prior to any | |
1414 | // probes starting. | |
1415 | ||
1416 | // Adds the condition expression to the front of the probe's body | |
1417 | static void | |
1418 | derived_probe_condition_inline (derived_probe *p) | |
1419 | { | |
1420 | expression* e = p->sole_location()->condition; | |
1421 | assert(e); | |
1422 | ||
1423 | if_statement *ifs = new if_statement (); | |
1424 | ifs->tok = e->tok; | |
1425 | ifs->thenblock = new next_statement (); | |
1426 | ifs->thenblock->tok = e->tok; | |
1427 | ifs->elseblock = NULL; | |
1428 | unary_expression *notex = new unary_expression (); | |
1429 | notex->op = "!"; | |
1430 | notex->tok = e->tok; | |
1431 | notex->operand = e; | |
1432 | ifs->condition = notex; | |
1433 | p->body = new block (ifs, p->body); | |
1434 | } | |
5d23847d FCE |
1435 | |
1436 | static int | |
1437 | semantic_pass_conditions (systemtap_session & sess) | |
1438 | { | |
ecf50eda JL |
1439 | map<derived_probe*, set<vardecl*> > vars_read_in_cond; |
1440 | map<derived_probe*, set<vardecl*> > vars_written_in_body; | |
1441 | ||
1442 | // do a first pass through the probes to ensure safety, inline any condition, | |
1443 | // and collect var usage | |
5d23847d FCE |
1444 | for (unsigned i = 0; i < sess.probes.size(); ++i) |
1445 | { | |
1446 | derived_probe* p = sess.probes[i]; | |
1447 | expression* e = p->sole_location()->condition; | |
ecf50eda | 1448 | |
5d23847d FCE |
1449 | if (e) |
1450 | { | |
ecf50eda JL |
1451 | varuse_collecting_visitor vcv_cond(sess); |
1452 | e->visit (& vcv_cond); | |
1453 | ||
1454 | if (!vcv_cond.written.empty()) | |
1455 | sess.print_error (SEMANTIC_ERROR (_("probe condition must not " | |
1456 | "modify any variables"), | |
1457 | e->tok)); | |
1458 | else if (vcv_cond.embedded_seen) | |
1459 | sess.print_error (SEMANTIC_ERROR (_("probe condition must not " | |
1460 | "include impure embedded-C"), | |
1461 | e->tok)); | |
1462 | ||
1463 | derived_probe_condition_inline(p); | |
1464 | ||
1465 | vars_read_in_cond[p].insert(vcv_cond.read.begin(), | |
1466 | vcv_cond.read.end()); | |
1467 | } | |
5d23847d | 1468 | |
ecf50eda JL |
1469 | varuse_collecting_visitor vcv_body(sess); |
1470 | p->body->visit (& vcv_body); | |
1471 | ||
1472 | vars_written_in_body[p].insert(vcv_body.written.begin(), | |
1473 | vcv_body.written.end()); | |
1474 | } | |
1475 | ||
1476 | // do a second pass to collect affected probes | |
ecf50eda JL |
1477 | for (unsigned i = 0; i < sess.probes.size(); ++i) |
1478 | { | |
1479 | derived_probe *p = sess.probes[i]; | |
1480 | ||
1481 | // for each variable this probe modifies... | |
1482 | set<vardecl*>::const_iterator var; | |
1483 | for (var = vars_written_in_body[p].begin(); | |
1484 | var != vars_written_in_body[p].end(); ++var) | |
1485 | { | |
1486 | // collect probes which could be affected | |
1487 | for (unsigned j = 0; j < sess.probes.size(); ++j) | |
5d23847d | 1488 | { |
ecf50eda JL |
1489 | if (vars_read_in_cond[sess.probes[j]].count(*var)) |
1490 | { | |
1491 | if (!p->probes_with_affected_conditions.count(sess.probes[j])) | |
1492 | { | |
1493 | p->probes_with_affected_conditions.insert(sess.probes[j]); | |
1494 | if (sess.verbose > 2) | |
1495 | clog << "probe " << i << " can affect condition of " | |
1496 | "probe " << j << endl; | |
1497 | } | |
ecf50eda | 1498 | } |
5d23847d | 1499 | } |
5d23847d | 1500 | } |
57148ee7 | 1501 | } |
5d23847d | 1502 | |
f161bd74 JL |
1503 | // PR18115: We create a begin probe which is artificially registered as |
1504 | // affecting every other probe. This will serve as the initializer so that | |
1505 | // other probe types with false conditions can be skipped (or registered as | |
1506 | // disabled) during module initialization. | |
1507 | ||
1508 | set<derived_probe*> targets; | |
1509 | for (unsigned i = 0; i < sess.probes.size(); ++i) | |
1510 | if (!vars_read_in_cond[sess.probes[i]].empty()) | |
1511 | targets.insert(sess.probes[i]); | |
1512 | ||
1513 | if (!targets.empty()) | |
1514 | { | |
1515 | stringstream ss("probe begin {}"); | |
1516 | ||
1517 | // no good token to choose here... let's just use the condition expression | |
1518 | // of one of the probes as the token | |
1519 | const token *tok = (*targets.begin())->sole_location()->condition->tok; | |
1520 | ||
1521 | probe *p = parse_synthetic_probe(sess, ss, tok); | |
1522 | if (!p) | |
1523 | throw SEMANTIC_ERROR (_("can't create cond initializer probe"), tok); | |
1524 | ||
1525 | vector<derived_probe*> dps; | |
1526 | derive_probes(sess, p, dps); | |
1527 | ||
1528 | // there should only be one | |
1529 | assert(dps.size() == 1); | |
1530 | ||
1531 | derived_probe* dp = dps[0]; | |
1532 | dp->probes_with_affected_conditions.insert(targets.begin(), | |
1533 | targets.end()); | |
1534 | sess.probes.push_back (dp); | |
1535 | dp->join_group (sess); | |
1536 | ||
1537 | // no need to manually do symresolution since body is empty | |
1538 | } | |
1539 | ||
5d23847d FCE |
1540 | return sess.num_errors(); |
1541 | } | |
1542 | ||
ac9ca50a MW |
1543 | // ------------------------------------------------------------------------ |
1544 | ||
1545 | ||
1546 | // Simple visitor that just goes through all embedded code blocks that | |
1547 | // are available at the end all the optimizations to register any | |
1548 | // relevant pragmas or other indicators found, so that session flags can | |
1549 | // be set that can be inspected at translation time to trigger any | |
1550 | // necessary initialization of code needed by the embedded code functions. | |
1551 | ||
1552 | // This is only for pragmas that don't have any other side-effect than | |
8af41ec2 | 1553 | // needing some initialization at module init time. Currently handles |
0af18f5a | 1554 | // /* pragma:vma */ /* pragma:unwind */ /* pragma:symbols */ /* pragma:lines */ |
ac9ca50a MW |
1555 | |
1556 | // /* pragma:uprobes */ is handled during the typeresolution_info pass. | |
2363d2a5 DB |
1557 | // /* pure */, /* unprivileged */. /* myproc-unprivileged */ and /* guru */ |
1558 | // are handled by the varuse_collecting_visitor. | |
ac9ca50a MW |
1559 | |
1560 | struct embeddedcode_info: public functioncall_traversing_visitor | |
1561 | { | |
1562 | protected: | |
1563 | systemtap_session& session; | |
1564 | ||
1565 | public: | |
1566 | embeddedcode_info (systemtap_session& s): session(s) { } | |
1567 | ||
1568 | void visit_embeddedcode (embeddedcode* c) | |
1569 | { | |
a057c85c | 1570 | if (! vma_tracker_enabled(session) |
ac9ca50a MW |
1571 | && c->code.find("/* pragma:vma */") != string::npos) |
1572 | { | |
ac9ca50a | 1573 | if (session.verbose > 2) |
4af765b2 | 1574 | clog << _F("Turning on task_finder vma_tracker, pragma:vma found in %s", |
5eb6ecb1 | 1575 | current_function->unmangled_name.to_string().c_str()) << endl; |
7f085e3f JS |
1576 | |
1577 | // PR15052: stapdyn doesn't have VMA-tracking yet. | |
1578 | if (session.runtime_usermode_p()) | |
dc09353a | 1579 | throw SEMANTIC_ERROR(_("VMA-tracking is only supported by the kernel runtime (PR15052)"), c->tok); |
7f085e3f JS |
1580 | |
1581 | enable_vma_tracker(session); | |
ac9ca50a | 1582 | } |
08badca8 MW |
1583 | |
1584 | if (! session.need_unwind | |
1585 | && c->code.find("/* pragma:unwind */") != string::npos) | |
1586 | { | |
1587 | if (session.verbose > 2) | |
1588 | clog << _F("Turning on unwind support, pragma:unwind found in %s", | |
5eb6ecb1 | 1589 | current_function->unmangled_name.to_string().c_str()) << endl; |
8af41ec2 MW |
1590 | session.need_unwind = true; |
1591 | } | |
1592 | ||
1593 | if (! session.need_symbols | |
1594 | && c->code.find("/* pragma:symbols */") != string::npos) | |
1595 | { | |
1596 | if (session.verbose > 2) | |
1597 | clog << _F("Turning on symbol data collecting, pragma:symbols found in %s", | |
5eb6ecb1 DS |
1598 | current_function->unmangled_name.to_string().c_str()) |
1599 | << endl; | |
8af41ec2 MW |
1600 | session.need_symbols = true; |
1601 | } | |
ee533a58 AJ |
1602 | |
1603 | if (! session.need_lines | |
1604 | && c->code.find("/* pragma:lines */") != string::npos) | |
1605 | { | |
1606 | if (session.verbose > 2) | |
1607 | clog << _F("Turning on debug line data collecting, pragma:lines found in %s", | |
5eb6ecb1 DS |
1608 | current_function->unmangled_name.to_string().c_str()) |
1609 | << endl; | |
dbfc9df8 | 1610 | session.need_lines = true; |
ee533a58 | 1611 | } |
ac9ca50a MW |
1612 | } |
1613 | }; | |
1614 | ||
1615 | void embeddedcode_info_pass (systemtap_session& s) | |
1616 | { | |
1617 | embeddedcode_info eci (s); | |
1618 | for (unsigned i=0; i<s.probes.size(); i++) | |
1619 | s.probes[i]->body->visit (& eci); | |
1620 | } | |
5d23847d | 1621 | |
07c17d67 GH |
1622 | // ------------------------------------------------------------------------ |
1623 | ||
2b066ec1 | 1624 | |
d2548fe7 SM |
1625 | // Simple visitor that collects all the regular expressions in the |
1626 | // file and adds them to the session DFA table. | |
1627 | ||
1628 | struct regex_collecting_visitor: public functioncall_traversing_visitor | |
1629 | { | |
1630 | protected: | |
1631 | systemtap_session& session; | |
1632 | ||
1633 | public: | |
1634 | regex_collecting_visitor (systemtap_session& s): session(s) { } | |
1635 | ||
1636 | void visit_regex_query (regex_query *q) { | |
d3bc48f0 | 1637 | functioncall_traversing_visitor::visit_regex_query (q); |
d2548fe7 | 1638 | |
47d349b1 | 1639 | string re = q->right->value; |
60cf5fae | 1640 | regex_to_stapdfa (&session, re, q->right->tok); |
d2548fe7 SM |
1641 | } |
1642 | }; | |
1643 | ||
1644 | // Go through the regex match invocations and generate corresponding DFAs. | |
e471dfb0 | 1645 | int gen_dfa_table (systemtap_session& s) |
d2548fe7 | 1646 | { |
e471dfb0 | 1647 | regex_collecting_visitor rcv(s); |
d2548fe7 SM |
1648 | |
1649 | for (unsigned i=0; i<s.probes.size(); i++) | |
1650 | { | |
e471dfb0 SM |
1651 | try |
1652 | { | |
1653 | s.probes[i]->body->visit (& rcv); | |
1654 | ||
1655 | if (s.probes[i]->sole_location()->condition) | |
1656 | s.probes[i]->sole_location()->condition->visit (& rcv); | |
1657 | } | |
1658 | catch (const semantic_error& e) | |
1659 | { | |
1660 | s.print_error (e); | |
1661 | } | |
d2548fe7 | 1662 | } |
e471dfb0 SM |
1663 | |
1664 | return s.num_errors(); | |
d2548fe7 SM |
1665 | } |
1666 | ||
1667 | // ------------------------------------------------------------------------ | |
1668 | ||
1669 | ||
2b066ec1 | 1670 | static int semantic_pass_symbols (systemtap_session&); |
c214bd6a DS |
1671 | static int semantic_pass_optimize1 (systemtap_session&); |
1672 | static int semantic_pass_optimize2 (systemtap_session&); | |
2b066ec1 | 1673 | static int semantic_pass_types (systemtap_session&); |
d02548c0 | 1674 | static int semantic_pass_vars (systemtap_session&); |
07c17d67 | 1675 | static int semantic_pass_stats (systemtap_session&); |
5d23847d | 1676 | static int semantic_pass_conditions (systemtap_session&); |
2b066ec1 FCE |
1677 | |
1678 | ||
40a393cd JS |
1679 | struct expression_build_no_more_visitor : public expression_visitor |
1680 | { | |
1681 | // Clear extra details from every expression, like DWARF type info, so that | |
1682 | // builders can safely release them in build_no_more. From here on out, | |
1683 | // we're back to basic types only. | |
1684 | void visit_expression(expression *e) | |
1685 | { | |
1686 | e->type_details.reset(); | |
1687 | } | |
1688 | }; | |
1689 | ||
1690 | static void | |
1691 | build_no_more (systemtap_session& s) | |
1692 | { | |
1693 | expression_build_no_more_visitor v; | |
1694 | ||
1695 | for (unsigned i=0; i<s.probes.size(); i++) | |
1696 | s.probes[i]->body->visit(&v); | |
1697 | ||
1698 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); | |
1699 | it != s.functions.end(); it++) | |
1700 | it->second->body->visit(&v); | |
1701 | ||
1702 | // Inform all derived_probe builders that we're done with | |
1703 | // all resolution, so it's time to release caches. | |
1704 | s.pattern_root->build_no_more (s); | |
1705 | } | |
1706 | ||
1707 | ||
1708 | ||
2b066ec1 FCE |
1709 | // Link up symbols to their declarations. Set the session's |
1710 | // files/probes/functions/globals vectors from the transitively | |
1711 | // reached set of stapfiles in s.library_files, starting from | |
20c6c071 | 1712 | // s.user_file. Perform automatic tapset inclusion and probe |
2b066ec1 FCE |
1713 | // alias expansion. |
1714 | static int | |
1715 | semantic_pass_symbols (systemtap_session& s) | |
1716 | { | |
1717 | symresolution_info sym (s); | |
1718 | ||
eb9ea966 JL |
1719 | // If we're listing functions, then we need to include all the files. Probe |
1720 | // aliases won't be visited/derived so all we gain are the functions, global | |
1721 | // variables, and any real probes (e.g. begin probes). NB: type resolution for | |
1722 | // a specific function arg may fail if it could only be determined from a | |
1723 | // function call in one of the skipped aliases. | |
bba368c5 | 1724 | if (s.dump_mode == systemtap_session::dump_functions) |
eb9ea966 JL |
1725 | { |
1726 | s.files.insert(s.files.end(), s.library_files.begin(), | |
1727 | s.library_files.end()); | |
1728 | } | |
ba48c27a | 1729 | else if (!s.user_files.empty()) |
bba368c5 | 1730 | { |
ba48c27a | 1731 | // Normal run: seed s.files with user_files and let it grow through the |
bba368c5 JL |
1732 | // find_* functions. NB: s.files can grow during this iteration, so |
1733 | // size() can return gradually increasing numbers. | |
ba48c27a | 1734 | s.files.insert (s.files.end(), s.user_files.begin(), s.user_files.end()); |
bba368c5 | 1735 | } |
eb9ea966 | 1736 | |
2b066ec1 FCE |
1737 | for (unsigned i = 0; i < s.files.size(); i++) |
1738 | { | |
e19ebcf7 | 1739 | assert_no_interrupts(); |
2b066ec1 FCE |
1740 | stapfile* dome = s.files[i]; |
1741 | ||
1742 | // Pass 1: add globals and functions to systemtap-session master list, | |
1743 | // so the find_* functions find them | |
e26c2f83 FCE |
1744 | // |
1745 | // NB: tapset global/function definitions may duplicate or conflict | |
1746 | // with those already in s.globals/functions. We need to deconflict | |
1747 | // here. | |
2b066ec1 FCE |
1748 | |
1749 | for (unsigned i=0; i<dome->globals.size(); i++) | |
e26c2f83 FCE |
1750 | { |
1751 | vardecl* g = dome->globals[i]; | |
1752 | for (unsigned j=0; j<s.globals.size(); j++) | |
1753 | { | |
1754 | vardecl* g2 = s.globals[j]; | |
1755 | if (g->name == g2->name) | |
1756 | { | |
dc09353a | 1757 | s.print_error (SEMANTIC_ERROR (_("conflicting global variables"), |
e26c2f83 FCE |
1758 | g->tok, g2->tok)); |
1759 | } | |
1760 | } | |
1761 | s.globals.push_back (g); | |
1762 | } | |
2b066ec1 FCE |
1763 | |
1764 | for (unsigned i=0; i<dome->functions.size(); i++) | |
e26c2f83 FCE |
1765 | { |
1766 | functiondecl* f = dome->functions[i]; | |
1767 | functiondecl* f2 = s.functions[f->name]; | |
1768 | if (f2 && f != f2) | |
1769 | { | |
dc09353a | 1770 | s.print_error (SEMANTIC_ERROR (_("conflicting functions"), |
e26c2f83 FCE |
1771 | f->tok, f2->tok)); |
1772 | } | |
1773 | s.functions[f->name] = f; | |
1774 | } | |
2b066ec1 | 1775 | |
e26c2f83 | 1776 | // NB: embeds don't conflict with each other |
54dfabe9 FCE |
1777 | for (unsigned i=0; i<dome->embeds.size(); i++) |
1778 | s.embeds.push_back (dome->embeds[i]); | |
1779 | ||
f8809d54 | 1780 | // Pass 2: derive probes and resolve any further symbols in the |
57148ee7 | 1781 | // derived results. |
2b066ec1 FCE |
1782 | |
1783 | for (unsigned i=0; i<dome->probes.size(); i++) | |
1784 | { | |
e19ebcf7 | 1785 | assert_no_interrupts(); |
2b066ec1 FCE |
1786 | probe* p = dome->probes [i]; |
1787 | vector<derived_probe*> dps; | |
1788 | ||
a971b891 FCE |
1789 | // much magic happens here: probe alias expansion, wildcard |
1790 | // matching, low-level derived_probe construction. | |
b4ceace2 | 1791 | derive_probes (s, p, dps); |
2b066ec1 FCE |
1792 | |
1793 | for (unsigned j=0; j<dps.size(); j++) | |
1794 | { | |
e19ebcf7 | 1795 | assert_no_interrupts(); |
2b066ec1 | 1796 | derived_probe* dp = dps[j]; |
b20febf3 FCE |
1797 | s.probes.push_back (dp); |
1798 | dp->join_group (s); | |
2b066ec1 | 1799 | |
57148ee7 | 1800 | try |
2b066ec1 | 1801 | { |
f80d9004 | 1802 | for (unsigned k=0; k<s.code_filters.size(); k++) |
8b095b45 | 1803 | s.code_filters[k]->replace (dp->body); |
f80d9004 | 1804 | |
2b066ec1 | 1805 | sym.current_function = 0; |
5227f1ea | 1806 | sym.current_probe = dp; |
2b066ec1 | 1807 | dp->body->visit (& sym); |
5d23847d FCE |
1808 | |
1809 | // Process the probe-point condition expression. | |
1810 | sym.current_function = 0; | |
1811 | sym.current_probe = 0; | |
1812 | if (dp->sole_location()->condition) | |
1813 | dp->sole_location()->condition->visit (& sym); | |
2b066ec1 FCE |
1814 | } |
1815 | catch (const semantic_error& e) | |
1816 | { | |
1817 | s.print_error (e); | |
1818 | } | |
1819 | } | |
1820 | } | |
f8809d54 JS |
1821 | |
1822 | // Pass 3: process functions | |
1823 | ||
1824 | for (unsigned i=0; i<dome->functions.size(); i++) | |
1825 | { | |
e19ebcf7 | 1826 | assert_no_interrupts(); |
f8809d54 JS |
1827 | functiondecl* fd = dome->functions[i]; |
1828 | ||
1829 | try | |
1830 | { | |
1831 | for (unsigned j=0; j<s.code_filters.size(); j++) | |
1832 | s.code_filters[j]->replace (fd->body); | |
1833 | ||
1834 | sym.current_function = fd; | |
1835 | sym.current_probe = 0; | |
1836 | fd->body->visit (& sym); | |
1837 | } | |
1838 | catch (const semantic_error& e) | |
1839 | { | |
1840 | s.print_error (e); | |
1841 | } | |
1842 | } | |
2b066ec1 | 1843 | } |
aa30ccd3 | 1844 | |
a07a2c28 LB |
1845 | if(s.systemtap_v_check){ |
1846 | for(unsigned i=0;i<s.globals.size();i++){ | |
1847 | if(s.globals[i]->systemtap_v_conditional) | |
4af765b2 | 1848 | s.print_warning(_("This global uses tapset constructs that are dependent on systemtap version"), s.globals[i]->tok); |
a07a2c28 LB |
1849 | } |
1850 | ||
1851 | for(map<string, functiondecl*>::const_iterator i=s.functions.begin();i != s.functions.end();++i){ | |
1852 | if(i->second->systemtap_v_conditional) | |
4af765b2 | 1853 | s.print_warning(_("This function uses tapset constructs that are dependent on systemtap version"), i->second->tok); |
a07a2c28 LB |
1854 | } |
1855 | ||
1856 | for(unsigned i=0;i<s.probes.size();i++){ | |
1857 | vector<probe*> sysvc; | |
1858 | s.probes[i]->collect_derivation_chain(sysvc); | |
1859 | for(unsigned j=0;j<sysvc.size();j++){ | |
1860 | if(sysvc[j]->systemtap_v_conditional) | |
4af765b2 | 1861 | s.print_warning(_("This probe uses tapset constructs that are dependent on systemtap version"), sysvc[j]->tok); |
a07a2c28 | 1862 | if(sysvc[j]->get_alias() && sysvc[j]->get_alias()->systemtap_v_conditional) |
4af765b2 | 1863 | s.print_warning(_("This alias uses tapset constructs that are dependent on systemtap version"), sysvc[j]->get_alias()->tok); |
a07a2c28 LB |
1864 | } |
1865 | } | |
1866 | } | |
1867 | ||
7e41d3dc | 1868 | return s.num_errors(); // all those print_error calls |
2b066ec1 FCE |
1869 | } |
1870 | ||
1871 | ||
0a102c82 SC |
1872 | // Keep unread global variables for probe end value display. |
1873 | void add_global_var_display (systemtap_session& s) | |
1874 | { | |
bba368c5 JL |
1875 | // Don't generate synthetic end probes when in listing mode; it would clutter |
1876 | // up the list of probe points with "end ...". In fact, don't bother in any | |
1877 | // dump mode at all, since it'll never be used. | |
1878 | if (s.dump_mode) return; | |
3438f38f | 1879 | |
313db8e6 | 1880 | varuse_collecting_visitor vut(s); |
9d8a6ba3 | 1881 | |
0a102c82 SC |
1882 | for (unsigned i=0; i<s.probes.size(); i++) |
1883 | { | |
1884 | s.probes[i]->body->visit (& vut); | |
1885 | ||
1886 | if (s.probes[i]->sole_location()->condition) | |
1887 | s.probes[i]->sole_location()->condition->visit (& vut); | |
1888 | } | |
1889 | ||
1890 | for (unsigned g=0; g < s.globals.size(); g++) | |
1891 | { | |
1892 | vardecl* l = s.globals[g]; | |
9d8a6ba3 SC |
1893 | if ((vut.read.find (l) != vut.read.end() |
1894 | && vut.used.find (l) != vut.used.end()) | |
e491a713 | 1895 | || vut.written.find (l) == vut.written.end()) |
0a102c82 SC |
1896 | continue; |
1897 | ||
b5852334 | 1898 | // Don't generate synthetic end probes for unread globals |
5ae31731 FCE |
1899 | // declared only within tapsets. (RHBZ 468139), but rather |
1900 | // only within the end-user script. | |
1901 | ||
7584f162 RA |
1902 | bool tapset_global = false; |
1903 | for (size_t m=0; m < s.library_files.size(); m++) | |
1904 | { | |
1905 | for (size_t n=0; n < s.library_files[m]->globals.size(); n++) | |
1906 | { | |
1907 | if (l->name == s.library_files[m]->globals[n]->name) | |
1908 | {tapset_global = true; break;} | |
1909 | } | |
1910 | } | |
1911 | if (tapset_global) | |
1912 | continue; | |
5ae31731 | 1913 | |
101b0805 JS |
1914 | stringstream code; |
1915 | code << "probe end {" << endl; | |
d5e178c1 | 1916 | |
9fef07ff | 1917 | string format = l->unmangled_name; |
0a102c82 | 1918 | |
101b0805 | 1919 | string indexes; |
96c3fced | 1920 | string foreach_value; |
101b0805 | 1921 | if (!l->index_types.empty()) |
0a102c82 | 1922 | { |
101b0805 JS |
1923 | // Add index values to the printf format, and prepare |
1924 | // a simple list of indexes for passing around elsewhere | |
1925 | format += "["; | |
1926 | for (size_t i = 0; i < l->index_types.size(); ++i) | |
e071e49b | 1927 | { |
101b0805 | 1928 | if (i > 0) |
e071e49b | 1929 | { |
101b0805 JS |
1930 | indexes += ","; |
1931 | format += ","; | |
e071e49b | 1932 | } |
101b0805 | 1933 | indexes += "__idx" + lex_cast(i); |
ead25cf5 | 1934 | if (l->index_types[i] == pe_string) |
101b0805 | 1935 | format += "\\\"%#s\\\""; |
ead25cf5 | 1936 | else |
101b0805 | 1937 | format += "%#d"; |
ead25cf5 | 1938 | } |
101b0805 | 1939 | format += "]"; |
0a102c82 | 1940 | |
101b0805 | 1941 | // Iterate over all indexes in the array, sorted by decreasing value |
96c3fced JS |
1942 | code << "foreach ("; |
1943 | if (l->type != pe_stats) | |
1944 | { | |
1945 | foreach_value = "__val"; | |
1946 | code << foreach_value << " = "; | |
1947 | } | |
9fef07ff | 1948 | code << "[" << indexes << "] in " << l->unmangled_name << "-)" << endl; |
101b0805 JS |
1949 | } |
1950 | else if (l->type == pe_stats) | |
1951 | { | |
1952 | // PR7053: Check scalar globals for empty aggregate | |
9fef07ff DS |
1953 | code << "if (@count(" << l->unmangled_name << ") == 0)" << endl; |
1954 | code << "printf(\"" << l->unmangled_name << " @count=0x0\\n\")" << endl; | |
101b0805 JS |
1955 | code << "else" << endl; |
1956 | } | |
e491a713 | 1957 | |
101b0805 JS |
1958 | static const string stats[] = { "@count", "@min", "@max", "@sum", "@avg" }; |
1959 | const string stats_format = | |
1960 | (strverscmp(s.compatible.c_str(), "1.4") >= 0) ? "%#d" : "%#x"; | |
e071e49b | 1961 | |
101b0805 JS |
1962 | // Fill in the printf format for values |
1963 | if (l->type == pe_stats) | |
1964 | for (size_t i = 0; i < sizeof(stats)/sizeof(stats[0]); ++i) | |
1965 | format += " " + stats[i] + "=" + stats_format; | |
1966 | else if (l->type == pe_string) | |
1967 | format += "=\\\"%#s\\\""; | |
1968 | else | |
1969 | format += "=%#x"; | |
1970 | format += "\\n"; | |
1971 | ||
1972 | // Output the actual printf | |
1973 | code << "printf (\"" << format << "\""; | |
57148ee7 | 1974 | |
101b0805 | 1975 | // Feed indexes to the printf, and include them in the value |
9fef07ff | 1976 | string value = !foreach_value.empty() ? foreach_value : string(l->unmangled_name); |
101b0805 JS |
1977 | if (!l->index_types.empty()) |
1978 | { | |
1979 | code << "," << indexes; | |
96c3fced JS |
1980 | if (foreach_value.empty()) |
1981 | value += "[" + indexes + "]"; | |
0a102c82 SC |
1982 | } |
1983 | ||
101b0805 JS |
1984 | // Feed the actual values to the printf |
1985 | if (l->type == pe_stats) | |
1986 | for (size_t i = 0; i < sizeof(stats)/sizeof(stats[0]); ++i) | |
1987 | code << "," << stats[i] << "(" << value << ")"; | |
1988 | else | |
1989 | code << "," << value; | |
1990 | code << ")" << endl; | |
1991 | ||
1992 | // End of probe | |
1993 | code << "}" << endl; | |
1994 | ||
1995 | probe *p = parse_synthetic_probe (s, code, l->tok); | |
1996 | if (!p) | |
1997 | throw SEMANTIC_ERROR (_("can't create global var display"), l->tok); | |
1998 | ||
1999 | vector<derived_probe*> dps; | |
6d2685fe | 2000 | derive_probes (s, p, dps); |
0a102c82 SC |
2001 | for (unsigned i = 0; i < dps.size(); i++) |
2002 | { | |
2003 | derived_probe* dp = dps[i]; | |
2004 | s.probes.push_back (dp); | |
2005 | dp->join_group (s); | |
101b0805 JS |
2006 | |
2007 | // Repopulate symbol and type info | |
2008 | symresolution_info sym (s); | |
2009 | sym.current_function = 0; | |
2010 | sym.current_probe = dp; | |
2011 | dp->body->visit (& sym); | |
0a102c82 SC |
2012 | } |
2013 | ||
6d2685fe SC |
2014 | semantic_pass_types(s); |
2015 | // Mark that variable is read | |
0a102c82 SC |
2016 | vut.read.insert (l); |
2017 | } | |
2018 | } | |
2b066ec1 | 2019 | |
6120441d FL |
2020 | static void monitor_mode_read(systemtap_session& s) |
2021 | { | |
2022 | if (!s.monitor) return; | |
2023 | ||
2024 | stringstream code; | |
2025 | ||
3e3756f8 FCE |
2026 | unsigned long rough_max_json_size = 100 + |
2027 | s.globals.size() * 100 + | |
2028 | s.probes.size() * 200; | |
2029 | ||
2030 | code << "probe procfs(\"monitor_status\").read.maxsize(" << rough_max_json_size << ") {" << endl; | |
2031 | code << "try {"; // absorb .= overflows! | |
f6429b94 FL |
2032 | code << "elapsed = (jiffies()-__monitor_module_start)/HZ()" << endl; |
2033 | code << "hrs = elapsed/3600; mins = elapsed%3600/60; secs = elapsed%3600%60;" << endl; | |
1f3802d4 | 2034 | code << "$value .= sprintf(\"{\\n\")" << endl; |
19a81101 | 2035 | code << "$value .= sprintf(\"\\\"uptime\\\": \\\"%02d:%02d:%02d\\\",\\n\", hrs, mins, secs)" << endl; |
1f3802d4 FL |
2036 | code << "$value .= sprintf(\"\\\"uid\\\": \\\"%d\\\",\\n\", uid())" << endl; |
2037 | code << "$value .= sprintf(\"\\\"memory\\\": \\\"%s\\\",\\n\", module_size())" << endl; | |
2038 | code << "$value .= sprintf(\"\\\"module_name\\\": \\\"%s\\\",\\n\", module_name())" << endl; | |
6120441d | 2039 | |
d86502b0 | 2040 | code << "$value .= sprintf(\"\\\"globals\\\": {\\n\")" << endl; |
6120441d FL |
2041 | for (vector<vardecl*>::const_iterator it = s.globals.begin(); |
2042 | it != s.globals.end(); ++it) | |
2043 | { | |
f6429b94 FL |
2044 | if ((*it)->synthetic) continue; |
2045 | ||
1f3802d4 FL |
2046 | if (it != s.globals.begin()) |
2047 | code << "$value .= sprintf(\",\\n\")" << endl; | |
2048 | ||
38098f65 | 2049 | code << "$value .= sprintf(\"\\\"%s\\\":\", \"" << (*it)->unmangled_name << "\")" << endl; |
9e42a050 | 2050 | if ((*it)->arity == 0) |
38098f65 | 2051 | code << "$value .= string_quoted(sprint(" << (*it)->name << "))" << endl; |
9e42a050 | 2052 | else if ((*it)->arity > 0) |
38098f65 | 2053 | code << "$value .= sprintf(\"\\\"[%d]\\\"\", " << (*it)->maxsize << ")" << endl; |
6120441d | 2054 | } |
d86502b0 | 2055 | code << "$value .= sprintf(\"\\n},\\n\")" << endl; |
6120441d | 2056 | |
8fb73e48 | 2057 | code << "$value .= sprintf(\"\\\"probe_list\\\": [\\n\")" << endl; |
6120441d FL |
2058 | for (vector<derived_probe*>::const_iterator it = s.probes.begin(); |
2059 | it != s.probes.end(); ++it) | |
2060 | { | |
1f3802d4 FL |
2061 | if (it != s.probes.begin()) |
2062 | code << "$value .= sprintf(\",\\n\")" << endl; | |
2063 | ||
6120441d FL |
2064 | istringstream probe_point((*it)->sole_location()->str()); |
2065 | string name; | |
2066 | probe_point >> name; | |
aa5bc745 FL |
2067 | /* Escape quotes once for systemtap parser and once more for json parser */ |
2068 | name = lex_cast_qstring(lex_cast_qstring(name)); | |
6120441d | 2069 | |
c0d0d623 | 2070 | code << "$value .= sprintf(\"{%s\", __private___monitor_data_function_probes(" |
6120441d | 2071 | << it-s.probes.begin() << "))" << endl; |
aa5bc745 | 2072 | code << "$value .= sprintf(\"\\\"name\\\": %s}\", " << name << ")" << endl; |
6120441d | 2073 | } |
8fb73e48 | 2074 | code << "$value .= sprintf(\"\\n],\\n\")" << endl; |
1f3802d4 FL |
2075 | |
2076 | code << "$value .= sprintf(\"}\\n\")" << endl; | |
6120441d | 2077 | |
3e3756f8 | 2078 | code << "} catch(ex) { warn(\"JSON construction error: \" . ex) }" << endl; |
6120441d | 2079 | code << "}" << endl; |
6120441d FL |
2080 | probe* p = parse_synthetic_probe(s, code, 0); |
2081 | if (!p) | |
2082 | throw SEMANTIC_ERROR (_("can't create procfs probe"), 0); | |
2083 | ||
2084 | vector<derived_probe*> dps; | |
2085 | derive_probes (s, p, dps); | |
2086 | ||
2087 | derived_probe* dp = dps[0]; | |
2088 | s.probes.push_back (dp); | |
2089 | dp->join_group (s); | |
2090 | ||
32bcf988 | 2091 | // Repopulate symbol info |
6120441d FL |
2092 | symresolution_info sym (s); |
2093 | sym.current_function = 0; | |
2094 | sym.current_probe = dp; | |
2095 | dp->body->visit (&sym); | |
6120441d FL |
2096 | } |
2097 | ||
2098 | static void monitor_mode_write(systemtap_session& s) | |
2099 | { | |
2100 | if (!s.monitor) return; | |
2101 | ||
2102 | for (vector<derived_probe*>::const_iterator it = s.probes.begin(); | |
32bcf988 | 2103 | it != s.probes.end()-1; ++it) // Skip monitor read probe |
6120441d FL |
2104 | { |
2105 | vardecl* v = new vardecl; | |
1d9d91c2 | 2106 | v->unmangled_name = v->name = "__monitor_" + lex_cast(it-s.probes.begin()) + "_enabled"; |
6120441d FL |
2107 | v->tok = (*it)->tok; |
2108 | v->set_arity(0, (*it)->tok); | |
2109 | v->type = pe_long; | |
2110 | v->init = new literal_number(1); | |
2111 | v->synthetic = true; | |
2112 | s.globals.push_back(v); | |
2113 | ||
2114 | symbol* sym = new symbol; | |
2115 | sym->name = v->name; | |
2116 | sym->tok = v->tok; | |
2117 | sym->type = pe_long; | |
2118 | sym->referent = v; | |
2119 | ||
2120 | if ((*it)->sole_location()->condition) | |
2121 | { | |
2122 | logical_and_expr *e = new logical_and_expr; | |
2123 | e->tok = v->tok; | |
2124 | e->left = sym; | |
2125 | e->op = "&&"; | |
2126 | e->type = pe_long; | |
2127 | e->right = (*it)->sole_location()->condition; | |
2128 | (*it)->sole_location()->condition = e; | |
2129 | } | |
2130 | else | |
2131 | { | |
2132 | (*it)->sole_location()->condition = sym; | |
2133 | } | |
2134 | } | |
2135 | ||
2136 | stringstream code; | |
2137 | ||
2138 | code << "probe procfs(\"monitor_control\").write {" << endl; | |
2139 | ||
1d9d91c2 | 2140 | code << "if ($value == \"clear\") {"; |
6120441d FL |
2141 | for (vector<vardecl*>::const_iterator it = s.globals.begin(); |
2142 | it != s.globals.end(); ++it) | |
2143 | { | |
2144 | vardecl* v = *it; | |
f6429b94 FL |
2145 | |
2146 | if (v->synthetic) continue; | |
2147 | ||
6120441d FL |
2148 | if (v->arity == 0 && v->init) |
2149 | { | |
2150 | if (v->type == pe_long) | |
2151 | { | |
2152 | literal_number* ln = dynamic_cast<literal_number*>(v->init); | |
2153 | code << v->name << " = " << ln->value << endl; | |
2154 | } | |
2155 | else if (v->type == pe_string) | |
2156 | { | |
2157 | literal_string* ln = dynamic_cast<literal_string*>(v->init); | |
2158 | code << v->name << " = " << lex_cast_qstring(ln->value) << endl; | |
2159 | } | |
2160 | } | |
2161 | else | |
2162 | { | |
2163 | // For scalar elements with no initial values, we reset to 0 or empty as | |
2164 | // done with arrays and aggregates. | |
2165 | code << "delete " << v->name << endl; | |
2166 | } | |
2167 | } | |
6120441d | 2168 | |
32bcf988 | 2169 | code << "} else if ($value == \"resume\") {" << endl; |
6120441d | 2170 | for (vector<derived_probe*>::const_iterator it = s.probes.begin(); |
32bcf988 FL |
2171 | it != s.probes.end()-1; ++it) |
2172 | { | |
2173 | code << " __monitor_" << it-s.probes.begin() << "_enabled" << " = 1" << endl; | |
2174 | } | |
2175 | ||
2176 | code << "} else if ($value == \"pause\") {" << endl; | |
2177 | for (vector<derived_probe*>::const_iterator it = s.probes.begin(); | |
2178 | it != s.probes.end()-1; ++it) | |
2179 | { | |
2180 | code << " __monitor_" << it-s.probes.begin() << "_enabled" << " = 0" << endl; | |
2181 | } | |
1a442bf4 FCE |
2182 | code << "} else if ($value == \"quit\") {" << endl; |
2183 | code << " exit()" << endl; | |
32bcf988 FL |
2184 | code << "}"; |
2185 | ||
2186 | for (vector<derived_probe*>::const_iterator it = s.probes.begin(); | |
2187 | it != s.probes.end()-1; ++it) | |
6120441d | 2188 | { |
d86502b0 | 2189 | code << " if ($value == \"" << it-s.probes.begin() << "\")" |
6120441d FL |
2190 | << " __monitor_" << it-s.probes.begin() << "_enabled" << " ^= 1" << endl; |
2191 | } | |
2192 | ||
2193 | code << "}" << endl; | |
2194 | ||
2195 | probe* p = parse_synthetic_probe(s, code, 0); | |
2196 | if (!p) | |
2197 | throw SEMANTIC_ERROR (_("can't create procfs probe"), 0); | |
2198 | ||
2199 | vector<derived_probe*> dps; | |
2200 | derive_probes (s, p, dps); | |
2201 | ||
2202 | derived_probe* dp = dps[0]; | |
2203 | s.probes.push_back (dp); | |
2204 | dp->join_group (s); | |
2205 | ||
32bcf988 | 2206 | // Repopulate symbol info |
87103d2b | 2207 | symresolution_info sym (s, /* omniscient-unmangled */ true); |
32bcf988 FL |
2208 | sym.current_function = 0; |
2209 | sym.current_probe = dp; | |
2210 | dp->body->visit (&sym); | |
2211 | } | |
2212 | ||
2213 | static void create_monitor_function(systemtap_session& s) | |
2214 | { | |
2215 | functiondecl* fd = new functiondecl; | |
2216 | fd->synthetic = true; | |
2217 | fd->unmangled_name = fd->name = "__private___monitor_data_function_probes"; | |
2218 | fd->type = pe_string; | |
2219 | ||
2220 | vardecl* v = new vardecl; | |
2221 | v->type = pe_long; | |
2222 | v->unmangled_name = v->name = "index"; | |
2223 | fd->formal_args.push_back(v); | |
2224 | ||
2225 | embeddedcode* ec = new embeddedcode; | |
2226 | string code; | |
2227 | code = "/* unprivileged */ /* pure */" | |
2228 | "const struct stap_probe *const p = &stap_probes[STAP_ARG_index];\n" | |
2229 | "if (likely (probe_timing(STAP_ARG_index))) {\n" | |
2230 | "struct stat_data *stats = _stp_stat_get (probe_timing(STAP_ARG_index), 0);\n" | |
2231 | "if (stats->count) {\n" | |
2232 | "int64_t avg = _stp_div64 (NULL, stats->sum, stats->count);\n" | |
2233 | "snprintf(_monitor_buf, STAP_MONITOR_READ,\n" | |
2234 | "\"\\\"index\\\": %zu, \\\"state\\\": \\\"%s\\\", \\\"hits\\\": %lld, " | |
2235 | "\\\"min\\\": %lld, \\\"avg\\\": %lld, \\\"max\\\": %lld, \",\n" | |
2236 | "p->index, p->cond_enabled ? \"on\" : \"off\", (long long) stats->count,\n" | |
2237 | "(long long) stats->min, (long long) avg, (long long) stats->max);\n" | |
2238 | "} else {\n" | |
2239 | "snprintf(_monitor_buf, STAP_MONITOR_READ,\n" | |
2240 | "\"\\\"index\\\": %zu, \\\"state\\\": \\\"%s\\\", \\\"hits\\\": %d, " | |
2241 | "\\\"min\\\": %d, \\\"avg\\\": %d, \\\"max\\\": %d, \",\n" | |
2242 | "p->index, p->cond_enabled ? \"on\" : \"off\", 0, 0, 0, 0);}}\n" | |
2243 | "STAP_RETURN(_monitor_buf);\n"; | |
2244 | ec->code = code; | |
2245 | fd->body = ec; | |
2246 | ||
2247 | s.functions[fd->name] = fd; | |
2248 | } | |
2249 | ||
2250 | static void monitor_mode_init(systemtap_session& s) | |
2251 | { | |
2252 | if (!s.monitor) return; | |
2253 | ||
2254 | vardecl* v = new vardecl; | |
2255 | v->unmangled_name = v->name = "__global___monitor_module_start"; | |
2256 | v->set_arity(0, 0); | |
2257 | v->type = pe_long; | |
2258 | v->synthetic = true; | |
2259 | s.globals.push_back(v); | |
2260 | ||
2261 | embeddedcode* ec = new embeddedcode; | |
2262 | ec->code = "#define STAP_MONITOR_READ 8192\n" | |
2263 | "static char _monitor_buf[STAP_MONITOR_READ];"; | |
2264 | s.embeds.push_back(ec); | |
2265 | ||
2266 | create_monitor_function(s); | |
2267 | monitor_mode_read(s); | |
2268 | monitor_mode_write(s); | |
2269 | ||
2270 | stringstream code; | |
2271 | code << "probe begin {" << endl; | |
2272 | code << "__monitor_module_start = jiffies()" << endl; | |
2273 | code << "}" << endl; | |
2274 | ||
2275 | probe* p = parse_synthetic_probe(s, code, 0); | |
2276 | if (!p) | |
2277 | throw SEMANTIC_ERROR (_("can't create begin probe"), 0); | |
2278 | ||
2279 | vector<derived_probe*> dps; | |
2280 | derive_probes (s, p, dps); | |
2281 | ||
2282 | derived_probe* dp = dps[0]; | |
2283 | s.probes.push_back (dp); | |
2284 | dp->join_group (s); | |
2285 | ||
2286 | // Repopulate symbol info | |
6120441d FL |
2287 | symresolution_info sym (s); |
2288 | sym.current_function = 0; | |
2289 | sym.current_probe = dp; | |
2290 | dp->body->visit (&sym); | |
6120441d FL |
2291 | } |
2292 | ||
2b066ec1 FCE |
2293 | int |
2294 | semantic_pass (systemtap_session& s) | |
2295 | { | |
59bafbe8 | 2296 | int rc = 0; |
20c6c071 | 2297 | |
57148ee7 | 2298 | try |
59bafbe8 | 2299 | { |
11a046b7 DS |
2300 | // FIXME: interactive mode, register_library_aliases handles |
2301 | // both aliases from library files *and* user scripts. It would | |
2302 | // be nice to have them in separate lists and register them | |
2303 | // separately. | |
59bafbe8 FCE |
2304 | s.register_library_aliases(); |
2305 | register_standard_tapsets(s); | |
57148ee7 | 2306 | |
5d23847d | 2307 | if (rc == 0) rc = semantic_pass_symbols (s); |
2e7f71c9 | 2308 | if (rc == 0) monitor_mode_init (s); |
5d23847d | 2309 | if (rc == 0) rc = semantic_pass_conditions (s); |
c0f56268 | 2310 | if (rc == 0) rc = semantic_pass_optimize1 (s); |
59bafbe8 | 2311 | if (rc == 0) rc = semantic_pass_types (s); |
e471dfb0 | 2312 | if (rc == 0) rc = gen_dfa_table(s); |
0a102c82 | 2313 | if (rc == 0) add_global_var_display (s); |
c0f56268 | 2314 | if (rc == 0) rc = semantic_pass_optimize2 (s); |
d02548c0 | 2315 | if (rc == 0) rc = semantic_pass_vars (s); |
07c17d67 | 2316 | if (rc == 0) rc = semantic_pass_stats (s); |
7b8548ee | 2317 | if (rc == 0) embeddedcode_info_pass (s); |
59bafbe8 FCE |
2318 | } |
2319 | catch (const semantic_error& e) | |
2320 | { | |
2321 | s.print_error (e); | |
21beacc9 | 2322 | rc ++; |
59bafbe8 | 2323 | } |
57148ee7 | 2324 | |
1ee0d3ba JL |
2325 | bool no_primary_probes = true; |
2326 | for (unsigned i = 0; i < s.probes.size(); i++) | |
2327 | if (s.is_primary_probe(s.probes[i])) | |
2328 | no_primary_probes = false; | |
2329 | ||
2330 | if (s.num_errors() == 0 && no_primary_probes && !s.dump_mode) | |
2331 | { | |
2332 | s.print_error(SEMANTIC_ERROR(_("no probes found"))); | |
2333 | rc ++; | |
2334 | } | |
2335 | ||
66facfa3 JS |
2336 | build_no_more (s); |
2337 | ||
f119a57f | 2338 | // PR11443 |
f5b1b8bc JS |
2339 | // NB: listing mode only cares whether we have any probes, |
2340 | // so all previous error conditions are disregarded. | |
bba368c5 JL |
2341 | if (s.dump_mode == systemtap_session::dump_matched_probes || |
2342 | s.dump_mode == systemtap_session::dump_matched_probes_vars) | |
1ee0d3ba | 2343 | rc = no_primary_probes; |
f119a57f | 2344 | |
eb9ea966 | 2345 | // If we're dumping functions, only error out if no functions were found |
bba368c5 | 2346 | if (s.dump_mode == systemtap_session::dump_functions) |
eb9ea966 JL |
2347 | rc = s.functions.empty(); |
2348 | ||
2b066ec1 FCE |
2349 | return rc; |
2350 | } | |
2351 | ||
2352 | ||
2b066ec1 FCE |
2353 | // ------------------------------------------------------------------------ |
2354 | // semantic processing: symbol resolution | |
2355 | ||
2356 | ||
87103d2b FCE |
2357 | symresolution_info::symresolution_info (systemtap_session& s, bool omniscient_unmangled): |
2358 | session (s), unmangled_p(omniscient_unmangled), current_function (0), current_probe (0) | |
2b066ec1 FCE |
2359 | { |
2360 | } | |
2361 | ||
2362 | ||
2363 | void | |
2364 | symresolution_info::visit_block (block* e) | |
2365 | { | |
2366 | for (unsigned i=0; i<e->statements.size(); i++) | |
2367 | { | |
57148ee7 | 2368 | try |
2b066ec1 FCE |
2369 | { |
2370 | e->statements[i]->visit (this); | |
2371 | } | |
2372 | catch (const semantic_error& e) | |
2373 | { | |
2374 | session.print_error (e); | |
2375 | } | |
2376 | } | |
2377 | } | |
2378 | ||
2379 | ||
69c68955 FCE |
2380 | void |
2381 | symresolution_info::visit_foreach_loop (foreach_loop* e) | |
2382 | { | |
2383 | for (unsigned i=0; i<e->indexes.size(); i++) | |
2384 | e->indexes[i]->visit (this); | |
3040bf3a | 2385 | for (unsigned i=0; i<e->array_slice.size(); i++) |
45af9d1b | 2386 | if (e->array_slice[i]) |
3040bf3a | 2387 | e->array_slice[i]->visit(this); |
69c68955 | 2388 | |
57148ee7 | 2389 | symbol *array = NULL; |
d02548c0 GH |
2390 | hist_op *hist = NULL; |
2391 | classify_indexable (e->base, array, hist); | |
69c68955 | 2392 | |
d02548c0 GH |
2393 | if (array) |
2394 | { | |
2395 | if (!array->referent) | |
57148ee7 | 2396 | { |
2e526dab | 2397 | vardecl* d = find_var (array->name, e->indexes.size (), array->tok); |
d02548c0 | 2398 | if (d) |
38bf68a8 | 2399 | { |
d02548c0 | 2400 | array->referent = d; |
38bf68a8 MC |
2401 | array->name = d->name; |
2402 | } | |
d02548c0 | 2403 | else |
60bebf58 JS |
2404 | { |
2405 | stringstream msg; | |
4af765b2 | 2406 | msg << _F("unresolved arity-%zu global array %s, missing global declaration?", |
7371cd19 | 2407 | e->indexes.size(), array->name.to_string().c_str()); |
980f1e82 | 2408 | throw SEMANTIC_ERROR (msg.str(), array->tok); |
60bebf58 | 2409 | } |
d02548c0 | 2410 | } |
69c68955 | 2411 | |
9972a915 | 2412 | if (!e->array_slice.empty() && e->array_slice.size() != e->indexes.size()) |
3040bf3a AJ |
2413 | { |
2414 | stringstream msg; | |
2415 | msg << _F("unresolved arity-%zu global array %s, missing global declaration?", | |
7371cd19 | 2416 | e->array_slice.size(), array->name.to_string().c_str()); |
3040bf3a AJ |
2417 | throw SEMANTIC_ERROR (msg.str(), array->tok); |
2418 | } | |
d02548c0 | 2419 | } |
57148ee7 | 2420 | else |
d02548c0 GH |
2421 | { |
2422 | assert (hist); | |
2423 | hist->visit (this); | |
2424 | } | |
69c68955 | 2425 | |
c261711d JS |
2426 | if (e->value) |
2427 | e->value->visit (this); | |
2428 | ||
27f21e8c DS |
2429 | if (e->limit) |
2430 | e->limit->visit (this); | |
2431 | ||
69c68955 FCE |
2432 | e->block->visit (this); |
2433 | } | |
2434 | ||
d02548c0 | 2435 | |
57148ee7 | 2436 | struct |
d98d459c GH |
2437 | delete_statement_symresolution_info: |
2438 | public traversing_visitor | |
2439 | { | |
2440 | symresolution_info *parent; | |
2441 | ||
2442 | delete_statement_symresolution_info (symresolution_info *p): | |
2443 | parent(p) | |
2444 | {} | |
2445 | ||
2446 | void visit_arrayindex (arrayindex* e) | |
2447 | { | |
9972a915 | 2448 | parent->visit_arrayindex(e, true); |
d98d459c | 2449 | } |
a98c930b | 2450 | |
d98d459c GH |
2451 | void visit_functioncall (functioncall* e) |
2452 | { | |
2453 | parent->visit_functioncall (e); | |
2454 | } | |
2455 | ||
2456 | void visit_symbol (symbol* e) | |
2457 | { | |
2458 | if (e->referent) | |
2459 | return; | |
57148ee7 | 2460 | |
2e526dab | 2461 | vardecl* d = parent->find_var (e->name, -1, e->tok); |
d98d459c GH |
2462 | if (d) |
2463 | e->referent = d; | |
2464 | else | |
dc09353a | 2465 | throw SEMANTIC_ERROR (_("unresolved array in delete statement"), e->tok); |
d98d459c GH |
2466 | } |
2467 | }; | |
2468 | ||
57148ee7 | 2469 | void |
d98d459c GH |
2470 | symresolution_info::visit_delete_statement (delete_statement* s) |
2471 | { | |
2472 | delete_statement_symresolution_info di (this); | |
2473 | s->value->visit (&di); | |
2474 | } | |
2475 | ||
69c68955 | 2476 | |
2b066ec1 FCE |
2477 | void |
2478 | symresolution_info::visit_symbol (symbol* e) | |
2479 | { | |
2480 | if (e->referent) | |
2481 | return; | |
2482 | ||
2e526dab | 2483 | vardecl* d = find_var (e->name, 0, e->tok); |
2b066ec1 | 2484 | if (d) |
38bf68a8 | 2485 | { |
2b066ec1 | 2486 | e->referent = d; |
38bf68a8 MC |
2487 | e->name = d->name; |
2488 | } | |
2b066ec1 FCE |
2489 | else |
2490 | { | |
2491 | // new local | |
2492 | vardecl* v = new vardecl; | |
62ac4eaf | 2493 | v->unmangled_name = v->name = e->name; |
2b066ec1 | 2494 | v->tok = e->tok; |
58701b78 | 2495 | v->set_arity(0, e->tok); |
2b066ec1 FCE |
2496 | if (current_function) |
2497 | current_function->locals.push_back (v); | |
2498 | else if (current_probe) | |
2499 | current_probe->locals.push_back (v); | |
2500 | else | |
5d23847d | 2501 | // must be probe-condition expression |
dc09353a | 2502 | throw SEMANTIC_ERROR (_("probe condition must not reference undeclared global"), e->tok); |
2b066ec1 FCE |
2503 | e->referent = v; |
2504 | } | |
2505 | } | |
2506 | ||
2507 | ||
2508 | void | |
2509 | symresolution_info::visit_arrayindex (arrayindex* e) | |
9972a915 AJ |
2510 | { |
2511 | visit_arrayindex(e, false); | |
2512 | } | |
2513 | ||
2514 | void | |
2515 | symresolution_info::visit_arrayindex (arrayindex* e, bool wildcard_ok) | |
2b066ec1 FCE |
2516 | { |
2517 | for (unsigned i=0; i<e->indexes.size(); i++) | |
45af9d1b AJ |
2518 | { |
2519 | // assuming that if NULL, it was originally a wildcard (*) | |
2520 | if (e->indexes[i] == NULL) | |
9972a915 AJ |
2521 | { |
2522 | if (!wildcard_ok) | |
2523 | throw SEMANTIC_ERROR(_("wildcard not allowed in array index"), e->tok); | |
2524 | } | |
45af9d1b AJ |
2525 | else |
2526 | e->indexes[i]->visit (this); | |
2527 | } | |
2b066ec1 | 2528 | |
57148ee7 | 2529 | symbol *array = NULL; |
d02548c0 GH |
2530 | hist_op *hist = NULL; |
2531 | classify_indexable(e->base, array, hist); | |
2b066ec1 | 2532 | |
d02548c0 | 2533 | if (array) |
313b2f74 | 2534 | { |
d02548c0 GH |
2535 | if (array->referent) |
2536 | return; | |
2537 | ||
2e526dab | 2538 | vardecl* d = find_var (array->name, e->indexes.size (), array->tok); |
d02548c0 | 2539 | if (d) |
38bf68a8 | 2540 | { |
d02548c0 | 2541 | array->referent = d; |
38bf68a8 MC |
2542 | array->name = d->name; |
2543 | } | |
313b2f74 | 2544 | else |
d02548c0 | 2545 | { |
60bebf58 | 2546 | stringstream msg; |
4af765b2 | 2547 | msg << _F("unresolved arity-%zu global array %s, missing global declaration?", |
7371cd19 | 2548 | e->indexes.size(), array->name.to_string().c_str()); |
dc09353a | 2549 | throw SEMANTIC_ERROR (msg.str(), e->tok); |
57148ee7 | 2550 | } |
d02548c0 GH |
2551 | } |
2552 | else | |
2553 | { | |
2554 | assert (hist); | |
2555 | hist->visit (this); | |
313b2f74 | 2556 | } |
2b066ec1 FCE |
2557 | } |
2558 | ||
2559 | ||
e225e273 AJ |
2560 | void |
2561 | symresolution_info::visit_array_in (array_in* e) | |
2562 | { | |
9972a915 | 2563 | visit_arrayindex(e->operand, true); |
e225e273 AJ |
2564 | } |
2565 | ||
2b066ec1 FCE |
2566 | |
2567 | void | |
2568 | symresolution_info::visit_functioncall (functioncall* e) | |
2569 | { | |
5d23847d FCE |
2570 | // XXX: we could relax this, if we're going to examine the |
2571 | // vartracking data recursively. See testsuite/semko/fortytwo.stp. | |
2572 | if (! (current_function || current_probe)) | |
2573 | { | |
2574 | // must be probe-condition expression | |
dc09353a | 2575 | throw SEMANTIC_ERROR (_("probe condition must not reference function"), e->tok); |
5d23847d FCE |
2576 | } |
2577 | ||
2b066ec1 FCE |
2578 | for (unsigned i=0; i<e->args.size(); i++) |
2579 | e->args[i]->visit (this); | |
2580 | ||
7b5b30a8 | 2581 | if (!e->referents.empty()) |
2b066ec1 FCE |
2582 | return; |
2583 | ||
7b5b30a8 FL |
2584 | vector<functiondecl*> fds = find_functions (e->function, e->args.size (), e->tok); |
2585 | if (!fds.empty()) | |
2586 | { | |
2587 | e->referents = fds; | |
2588 | function_priority_order order; | |
2589 | stable_sort(e->referents.begin(), e->referents.end(), order); // preserve declaration order | |
2590 | e->function = e->referents[0]->name; | |
2591 | } | |
2b066ec1 | 2592 | else |
2a99f48f | 2593 | { |
4e9b3f99 JL |
2594 | string sugs = levenshtein_suggest(e->function, collect_functions(), 5); // print 5 funcs |
2595 | throw SEMANTIC_ERROR(_F("unresolved function%s", | |
2596 | sugs.empty() ? "" : (_(" (similar: ") + sugs + ")").c_str()), | |
2597 | e->tok); | |
2a99f48f | 2598 | } |
6120441d FL |
2599 | |
2600 | // In monitor mode, tapset functions used in the synthetic probe are not resolved and added | |
2601 | // to the master list at the same time as the other functions so we must add them here to | |
2602 | // allow the translator to generate the functions in the module. | |
2603 | if (session.monitor && session.functions.find(e->function) == session.functions.end()) | |
7b5b30a8 | 2604 | session.functions[e->function] = fds[0]; // no overload |
2b066ec1 FCE |
2605 | } |
2606 | ||
a07a2c28 LB |
2607 | /*find_var will return an argument other than zero if the name matches the var |
2608 | * name ie, if the current local name matches the name passed to find_var*/ | |
57148ee7 | 2609 | vardecl* |
47d349b1 | 2610 | symresolution_info::find_var (interned_string name, int arity, const token* tok) |
2b066ec1 | 2611 | { |
5d23847d FCE |
2612 | if (current_function || current_probe) |
2613 | { | |
2614 | // search locals | |
57148ee7 | 2615 | vector<vardecl*>& locals = (current_function ? |
5d23847d FCE |
2616 | current_function->locals : |
2617 | current_probe->locals); | |
57148ee7 FCE |
2618 | |
2619 | ||
5d23847d | 2620 | for (unsigned i=0; i<locals.size(); i++) |
60bebf58 | 2621 | if (locals[i]->name == name) |
5d23847d | 2622 | { |
58701b78 | 2623 | locals[i]->set_arity (arity, tok); |
5d23847d FCE |
2624 | return locals[i]; |
2625 | } | |
2626 | } | |
2b066ec1 | 2627 | |
313b2f74 GH |
2628 | // search function formal parameters (for scalars) |
2629 | if (arity == 0 && current_function) | |
2b066ec1 FCE |
2630 | for (unsigned i=0; i<current_function->formal_args.size(); i++) |
2631 | if (current_function->formal_args[i]->name == name) | |
8846477c FCE |
2632 | { |
2633 | // NB: no need to check arity here: formal args always scalar | |
58701b78 | 2634 | current_function->formal_args[i]->set_arity (0, tok); |
8846477c FCE |
2635 | return current_function->formal_args[i]; |
2636 | } | |
2b066ec1 | 2637 | |
313b2f74 | 2638 | // search processed globals |
87103d2b FCE |
2639 | string gname, pname; |
2640 | if (unmangled_p) | |
2641 | { | |
2642 | gname = pname = string(name); | |
2643 | } | |
2644 | else | |
2645 | { | |
2646 | gname = "__global_" + string(name); | |
2647 | pname = "__private_" + detox_path(tok->location.file->name) + string(name); | |
2648 | } | |
2b066ec1 | 2649 | for (unsigned i=0; i<session.globals.size(); i++) |
38bf68a8 | 2650 | { |
8f54215e | 2651 | if ((session.globals[i]->name == name && startswith(name, "__global_")) || |
38bf68a8 MC |
2652 | (session.globals[i]->name == gname) || |
2653 | (session.globals[i]->name == pname)) | |
8846477c | 2654 | { |
2e526dab FCE |
2655 | if (! session.suppress_warnings) |
2656 | { | |
2657 | vardecl* v = session.globals[i]; | |
101b0805 | 2658 | stapfile* f = tok->location.file; |
2e526dab | 2659 | // clog << "resolved " << *tok << " to global " << *v->tok << endl; |
f6429b94 | 2660 | if (v->tok && v->tok->location.file != f && !f->synthetic) |
2e526dab | 2661 | { |
4af765b2 LB |
2662 | session.print_warning (_F("cross-file global variable reference to %s from", |
2663 | lex_cast(*v->tok).c_str()), tok); | |
2e526dab FCE |
2664 | } |
2665 | } | |
2a7153bf JS |
2666 | session.globals[i]->set_arity (arity, tok); |
2667 | return session.globals[i]; | |
8846477c | 2668 | } |
38bf68a8 | 2669 | } |
57148ee7 | 2670 | |
2b066ec1 FCE |
2671 | // search library globals |
2672 | for (unsigned i=0; i<session.library_files.size(); i++) | |
2673 | { | |
2674 | stapfile* f = session.library_files[i]; | |
2675 | for (unsigned j=0; j<f->globals.size(); j++) | |
84e5ea0f FCE |
2676 | { |
2677 | vardecl* g = f->globals[j]; | |
38bf68a8 | 2678 | if (g->name == gname) |
84e5ea0f | 2679 | { |
58701b78 | 2680 | g->set_arity (arity, tok); |
57148ee7 FCE |
2681 | |
2682 | // put library into the queue if not already there | |
2683 | if (find (session.files.begin(), session.files.end(), f) | |
84e5ea0f FCE |
2684 | == session.files.end()) |
2685 | session.files.push_back (f); | |
57148ee7 | 2686 | |
84e5ea0f FCE |
2687 | return g; |
2688 | } | |
2689 | } | |
2b066ec1 FCE |
2690 | } |
2691 | ||
2b066ec1 | 2692 | return 0; |
2b066ec1 FCE |
2693 | } |
2694 | ||
2695 | ||
7b5b30a8 FL |
2696 | vector<functiondecl*> |
2697 | symresolution_info::find_functions (const string& name, unsigned arity, const token *tok) | |
2b066ec1 | 2698 | { |
7b5b30a8 FL |
2699 | vector<functiondecl*> functions; |
2700 | functiondecl* last = 0; // used for error message | |
8f54215e | 2701 | |
f76427a2 | 2702 | // the common path |
8f54215e MC |
2703 | |
2704 | // internal global functions bypassing the parser, such as __global_dwarf_tvar_[gs]et | |
2705 | if ((session.functions.find(name) != session.functions.end()) && startswith(name, "__private_")) | |
2b066ec1 | 2706 | { |
f76427a2 FCE |
2707 | functiondecl* fd = session.functions[name]; |
2708 | assert (fd->name == name); | |
2709 | if (fd->formal_args.size() == arity) | |
7b5b30a8 FL |
2710 | functions.push_back(fd); |
2711 | else | |
2712 | last = fd; | |
2b066ec1 FCE |
2713 | } |
2714 | ||
7b5b30a8 FL |
2715 | // functions scanned by the parser are overloaded |
2716 | unsigned alternatives = session.overload_count[name]; | |
2717 | for (unsigned alt = 0; alt < alternatives; alt++) | |
8f54215e | 2718 | { |
7b5b30a8 FL |
2719 | bool found = false; // multiple inclusion guard |
2720 | string gname = "__global_" + string(name) + "__overload_" + lex_cast(alt); | |
2721 | string pname = "__private_" + detox_path(tok->location.file->name) + string(name) + | |
2722 | "__overload_" + lex_cast(alt); | |
8f54215e | 2723 | |
7b5b30a8 FL |
2724 | // tapset or user script global functions coming from the parser |
2725 | if (!found && session.functions.find(gname) != session.functions.end()) | |
2726 | { | |
2727 | functiondecl* fd = session.functions[gname]; | |
2728 | assert (fd->name == gname); | |
2729 | if (fd->formal_args.size() == arity) | |
2730 | { | |
2731 | functions.push_back(fd); | |
2732 | found = true; | |
2733 | } | |
2734 | else | |
2735 | last = fd; | |
2736 | } | |
8f54215e | 2737 | |
7b5b30a8 FL |
2738 | // tapset or user script private functions coming from the parser |
2739 | if (!found && session.functions.find(pname) != session.functions.end()) | |
2740 | { | |
2741 | functiondecl* fd = session.functions[pname]; | |
2742 | assert (fd->name == pname); | |
2743 | if (fd->formal_args.size() == arity) | |
2744 | { | |
2745 | functions.push_back(fd); | |
2746 | found = true; | |
2747 | } | |
2748 | else | |
2749 | last = fd; | |
2750 | } | |
8f54215e | 2751 | |
7b5b30a8 FL |
2752 | // search library functions |
2753 | for (unsigned i=0; !found && i<session.library_files.size(); i++) | |
2754 | { | |
2755 | stapfile* f = session.library_files[i]; | |
2756 | for (unsigned j=0; !found && j<f->functions.size(); j++) | |
2b066ec1 | 2757 | { |
7b5b30a8 FL |
2758 | if ((f->functions[j]->name == gname) || |
2759 | (f->functions[j]->name == pname)) | |
103c95fb | 2760 | { |
7b5b30a8 FL |
2761 | if (f->functions[j]->formal_args.size() == arity) |
2762 | { | |
2763 | // put library into the queue if not already there | |
2764 | if (0) // session.verbose_resolution | |
2765 | cerr << _F(" function %s is defined from %s", | |
2766 | name.c_str(), f->name.c_str()) << endl; | |
2767 | ||
2768 | if (find (session.files.begin(), session.files.end(), f) | |
2769 | == session.files.end()) | |
2770 | session.files.push_back (f); | |
2771 | // else .. print different message? | |
2772 | ||
2773 | functions.push_back(f->functions[j]); | |
2774 | found = true; | |
2775 | } | |
2776 | else | |
2777 | last = f->functions[j]; | |
103c95fb | 2778 | } |
2b066ec1 | 2779 | } |
7b5b30a8 | 2780 | } |
2b066ec1 FCE |
2781 | } |
2782 | ||
7b5b30a8 FL |
2783 | // suggest last found function with matching name |
2784 | if (last && functions.empty()) | |
2785 | { | |
2786 | throw SEMANTIC_ERROR(_F("arity mismatch found (function '%s' takes %zu args)", | |
2787 | name.c_str(), last->formal_args.size()), tok, last->tok); | |
2788 | } | |
2789 | ||
2790 | return functions; | |
2b066ec1 FCE |
2791 | } |
2792 | ||
4e9b3f99 JL |
2793 | set<string> |
2794 | symresolution_info::collect_functions(void) | |
2795 | { | |
2796 | set<string> funcs; | |
2797 | ||
2798 | for (map<string,functiondecl*>::const_iterator it = session.functions.begin(); | |
2799 | it != session.functions.end(); ++it) | |
5eb6ecb1 | 2800 | funcs.insert(it->second->unmangled_name); |
4e9b3f99 JL |
2801 | |
2802 | // search library functions | |
2803 | for (unsigned i=0; i<session.library_files.size(); i++) | |
2804 | { | |
2805 | stapfile* f = session.library_files[i]; | |
2806 | for (unsigned j=0; j<f->functions.size(); j++) | |
5eb6ecb1 | 2807 | funcs.insert(f->functions[j]->unmangled_name); |
4e9b3f99 | 2808 | } |
2b066ec1 | 2809 | |
4e9b3f99 JL |
2810 | return funcs; |
2811 | } | |
cbfbbf69 FCE |
2812 | |
2813 | // ------------------------------------------------------------------------ | |
2814 | // optimization | |
2815 | ||
2816 | ||
2817 | // Do away with functiondecls that are never (transitively) called | |
2818 | // from probes. | |
2819 | void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) | |
2820 | { | |
2821 | functioncall_traversing_visitor ftv; | |
2822 | for (unsigned i=0; i<s.probes.size(); i++) | |
5d23847d FCE |
2823 | { |
2824 | s.probes[i]->body->visit (& ftv); | |
2825 | if (s.probes[i]->sole_location()->condition) | |
2826 | s.probes[i]->sole_location()->condition->visit (& ftv); | |
2827 | } | |
f76427a2 FCE |
2828 | vector<functiondecl*> new_unused_functions; |
2829 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) | |
cbfbbf69 | 2830 | { |
f76427a2 | 2831 | functiondecl* fd = it->second; |
13133f2c | 2832 | if (ftv.seen.find(fd) == ftv.seen.end()) |
cbfbbf69 | 2833 | { |
ba48c27a | 2834 | if (! fd->synthetic && s.is_user_file(fd->tok->location.file->name)) |
7371cd19 | 2835 | s.print_warning (_F("Eliding unused function '%s'", |
5eb6ecb1 DS |
2836 | fd->unmangled_name.to_string().c_str()), |
2837 | fd->tok); | |
f76427a2 FCE |
2838 | // s.functions.erase (it); // NB: can't, since we're already iterating upon it |
2839 | new_unused_functions.push_back (fd); | |
cbfbbf69 | 2840 | relaxed_p = false; |
cbfbbf69 | 2841 | } |
f76427a2 FCE |
2842 | } |
2843 | for (unsigned i=0; i<new_unused_functions.size(); i++) | |
2844 | { | |
2845 | map<string,functiondecl*>::iterator where = s.functions.find (new_unused_functions[i]->name); | |
2846 | assert (where != s.functions.end()); | |
2847 | s.functions.erase (where); | |
2848 | if (s.tapset_compile_coverage) | |
2849 | s.unused_functions.push_back (new_unused_functions[i]); | |
cbfbbf69 FCE |
2850 | } |
2851 | } | |
2852 | ||
2853 | ||
2854 | // ------------------------------------------------------------------------ | |
2855 | ||
2856 | // Do away with local & global variables that are never | |
2857 | // written nor read. | |
cfd621bc | 2858 | void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations) |
cbfbbf69 | 2859 | { |
313db8e6 | 2860 | varuse_collecting_visitor vut(s); |
cfd621bc | 2861 | |
cbfbbf69 | 2862 | for (unsigned i=0; i<s.probes.size(); i++) |
5d23847d FCE |
2863 | { |
2864 | s.probes[i]->body->visit (& vut); | |
2865 | ||
2866 | if (s.probes[i]->sole_location()->condition) | |
2867 | s.probes[i]->sole_location()->condition->visit (& vut); | |
2868 | } | |
2869 | ||
cbfbbf69 FCE |
2870 | // NB: Since varuse_collecting_visitor also traverses down |
2871 | // actually called functions, we don't need to explicitly | |
2872 | // iterate over them. Uncalled ones should have been pruned | |
2873 | // in _opt1 above. | |
2874 | // | |
2875 | // for (unsigned i=0; i<s.functions.size(); i++) | |
2876 | // s.functions[i]->body->visit (& vut); | |
57148ee7 | 2877 | |
cbfbbf69 | 2878 | // Now in vut.read/written, we have a mixture of all locals, globals |
57148ee7 FCE |
2879 | |
2880 | for (unsigned i=0; i<s.probes.size(); i++) | |
cbfbbf69 FCE |
2881 | for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */) |
2882 | { | |
2883 | vardecl* l = s.probes[i]->locals[j]; | |
a9e8f7e0 | 2884 | |
a45664f4 | 2885 | // skip over "special" locals |
69aa668e | 2886 | if (l->synthetic) { j++; continue; } |
a45664f4 | 2887 | |
cbfbbf69 FCE |
2888 | if (vut.read.find (l) == vut.read.end() && |
2889 | vut.written.find (l) == vut.written.end()) | |
2890 | { | |
ba48c27a | 2891 | if (s.is_user_file(l->tok->location.file->name)) |
7371cd19 | 2892 | s.print_warning (_F("Eliding unused variable '%s'", |
5eb6ecb1 DS |
2893 | l->unmangled_name.to_string().c_str()), |
2894 | l->tok); | |
c3a3c0c9 WC |
2895 | if (s.tapset_compile_coverage) { |
2896 | s.probes[i]->unused_locals.push_back | |
2897 | (s.probes[i]->locals[j]); | |
2898 | } | |
cbfbbf69 FCE |
2899 | s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j); |
2900 | relaxed_p = false; | |
2901 | // don't increment j | |
2902 | } | |
2903 | else | |
27d24ae2 FCE |
2904 | { |
2905 | if (vut.written.find (l) == vut.written.end()) | |
cfd621bc | 2906 | if (iterations == 0 && ! s.suppress_warnings) |
64e0bc5a JL |
2907 | { |
2908 | set<string> vars; | |
2909 | vector<vardecl*>::iterator it; | |
2910 | for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++) | |
5eb6ecb1 | 2911 | vars.insert((*it)->unmangled_name); |
64e0bc5a | 2912 | for (it = s.globals.begin(); it != s.globals.end(); it++) |
5eb6ecb1 | 2913 | vars.insert((*it)->unmangled_name); |
64e0bc5a JL |
2914 | |
2915 | vars.erase(l->name); | |
2916 | string sugs = levenshtein_suggest(l->name, vars, 5); // suggest top 5 vars | |
2917 | s.print_warning (_F("never-assigned local variable '%s'%s", | |
5eb6ecb1 DS |
2918 | l->unmangled_name.to_string().c_str(), |
2919 | (sugs.empty() ? "" : | |
2920 | (_(" (similar: ") + sugs + ")")).c_str()), l->tok); | |
64e0bc5a | 2921 | } |
27d24ae2 FCE |
2922 | j++; |
2923 | } | |
cbfbbf69 | 2924 | } |
57148ee7 | 2925 | |
f76427a2 FCE |
2926 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
2927 | { | |
2928 | functiondecl *fd = it->second; | |
2929 | for (unsigned j=0; j<fd->locals.size(); /* see below */) | |
2930 | { | |
2931 | vardecl* l = fd->locals[j]; | |
2932 | if (vut.read.find (l) == vut.read.end() && | |
2933 | vut.written.find (l) == vut.written.end()) | |
2934 | { | |
ba48c27a | 2935 | if (s.is_user_file(l->tok->location.file->name)) |
7371cd19 | 2936 | s.print_warning (_F("Eliding unused variable '%s'", |
5eb6ecb1 DS |
2937 | l->unmangled_name.to_string().c_str()), |
2938 | l->tok); | |
f76427a2 FCE |
2939 | if (s.tapset_compile_coverage) { |
2940 | fd->unused_locals.push_back (fd->locals[j]); | |
2941 | } | |
2942 | fd->locals.erase(fd->locals.begin() + j); | |
2943 | relaxed_p = false; | |
2944 | // don't increment j | |
2945 | } | |
2946 | else | |
2947 | { | |
2948 | if (vut.written.find (l) == vut.written.end()) | |
2949 | if (iterations == 0 && ! s.suppress_warnings) | |
2950 | { | |
64e0bc5a | 2951 | set<string> vars; |
f76427a2 FCE |
2952 | vector<vardecl*>::iterator it; |
2953 | for (it = fd->formal_args.begin() ; | |
2954 | it != fd->formal_args.end(); it++) | |
5eb6ecb1 | 2955 | vars.insert((*it)->unmangled_name); |
f76427a2 | 2956 | for (it = fd->locals.begin(); it != fd->locals.end(); it++) |
5eb6ecb1 | 2957 | vars.insert((*it)->unmangled_name); |
f76427a2 | 2958 | for (it = s.globals.begin(); it != s.globals.end(); it++) |
5eb6ecb1 | 2959 | vars.insert((*it)->unmangled_name); |
f76427a2 | 2960 | |
64e0bc5a JL |
2961 | vars.erase(l->name); |
2962 | string sugs = levenshtein_suggest(l->name, vars, 5); // suggest top 5 vars | |
2963 | s.print_warning (_F("never-assigned local variable '%s'%s", | |
5eb6ecb1 DS |
2964 | l->unmangled_name.to_string().c_str(), |
2965 | (sugs.empty() ? "" : | |
2966 | (_(" (similar: ") + sugs + ")")).c_str()), l->tok); | |
f76427a2 | 2967 | } |
cfd621bc | 2968 | |
f76427a2 FCE |
2969 | j++; |
2970 | } | |
2971 | } | |
2972 | } | |
cbfbbf69 FCE |
2973 | for (unsigned i=0; i<s.globals.size(); /* see below */) |
2974 | { | |
2975 | vardecl* l = s.globals[i]; | |
2976 | if (vut.read.find (l) == vut.read.end() && | |
2977 | vut.written.find (l) == vut.written.end()) | |
2978 | { | |
ba48c27a | 2979 | if (s.is_user_file(l->tok->location.file->name)) |
7371cd19 | 2980 | s.print_warning (_F("Eliding unused variable '%s'", |
5eb6ecb1 DS |
2981 | l->unmangled_name.to_string().c_str()), |
2982 | l->tok); | |
c3a3c0c9 | 2983 | if (s.tapset_compile_coverage) { |
0a102c82 | 2984 | s.unused_globals.push_back(s.globals[i]); |
c3a3c0c9 | 2985 | } |
0a102c82 SC |
2986 | s.globals.erase(s.globals.begin() + i); |
2987 | relaxed_p = false; | |
2988 | // don't increment i | |
cbfbbf69 FCE |
2989 | } |
2990 | else | |
27d24ae2 | 2991 | { |
cfd621bc FCE |
2992 | if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer |
2993 | if (iterations == 0 && ! s.suppress_warnings) | |
2994 | { | |
64e0bc5a | 2995 | set<string> vars; |
cfd621bc FCE |
2996 | vector<vardecl*>::iterator it; |
2997 | for (it = s.globals.begin(); it != s.globals.end(); it++) | |
5eb6ecb1 DS |
2998 | if (l->name != (*it)->unmangled_name) |
2999 | vars.insert((*it)->unmangled_name); | |
57148ee7 | 3000 | |
64e0bc5a JL |
3001 | string sugs = levenshtein_suggest(l->name, vars, 5); // suggest top 5 vars |
3002 | s.print_warning (_F("never-assigned global variable '%s'%s", | |
5eb6ecb1 DS |
3003 | l->unmangled_name.to_string().c_str(), |
3004 | (sugs.empty() ? "" : | |
3005 | (_(" (similar: ") + sugs + ")")).c_str()), | |
3006 | l->tok); | |
cfd621bc FCE |
3007 | } |
3008 | ||
27d24ae2 FCE |
3009 | i++; |
3010 | } | |
cbfbbf69 FCE |
3011 | } |
3012 | } | |
3013 | ||
3014 | ||
3015 | // ------------------------------------------------------------------------ | |
3016 | ||
8bda6498 | 3017 | struct dead_assignment_remover: public update_visitor |
cbfbbf69 FCE |
3018 | { |
3019 | systemtap_session& session; | |
3020 | bool& relaxed_p; | |
3021 | const varuse_collecting_visitor& vut; | |
cbfbbf69 FCE |
3022 | |
3023 | dead_assignment_remover(systemtap_session& s, bool& r, | |
57148ee7 | 3024 | const varuse_collecting_visitor& v): |
8bda6498 | 3025 | session(s), relaxed_p(r), vut(v) {} |
cbfbbf69 FCE |
3026 | |
3027 | void visit_assignment (assignment* e); | |
f4fe2e93 | 3028 | void visit_try_block (try_block *s); |
cbfbbf69 FCE |
3029 | }; |
3030 | ||
3031 | ||
bd70b999 JS |
3032 | // symbol_fetcher augmented to allow target-symbol types, but NULLed. |
3033 | struct assignment_symbol_fetcher | |
3034 | : public symbol_fetcher | |
3035 | { | |
3036 | assignment_symbol_fetcher (symbol *&sym): symbol_fetcher(sym) | |
3037 | {} | |
3038 | ||
dabd71bb | 3039 | void visit_target_symbol (target_symbol*) |
bd70b999 JS |
3040 | { |
3041 | sym = NULL; | |
3042 | } | |
3043 | ||
dabd71bb | 3044 | void visit_atvar_op (atvar_op*) |
bd70b999 JS |
3045 | { |
3046 | sym = NULL; | |
3047 | } | |
3048 | ||
dabd71bb | 3049 | void visit_cast_op (cast_op*) |
bd70b999 JS |
3050 | { |
3051 | sym = NULL; | |
3052 | } | |
3053 | ||
dabd71bb | 3054 | void visit_autocast_op (autocast_op*) |
bd70b999 JS |
3055 | { |
3056 | sym = NULL; | |
3057 | } | |
3058 | ||
3059 | void throwone (const token* t) | |
3060 | { | |
3061 | if (t->type == tok_operator && t->content == ".") | |
3062 | // guess someone misused . in $foo->bar.baz expression | |
3063 | // XXX why are we only checking this in lvalues? | |
3064 | throw SEMANTIC_ERROR (_("Expecting lvalue expression, try -> instead"), t); | |
3065 | else | |
3066 | throw SEMANTIC_ERROR (_("Expecting lvalue expression"), t); | |
3067 | } | |
3068 | }; | |
3069 | ||
3070 | symbol * | |
3071 | get_assignment_symbol_within_expression (expression *e) | |
3072 | { | |
3073 | symbol *sym = NULL; | |
3074 | assignment_symbol_fetcher fetcher(sym); | |
3075 | e->visit (&fetcher); | |
3076 | return sym; // NB: may be null! | |
3077 | } | |
3078 | ||
3079 | ||
cbfbbf69 FCE |
3080 | void |
3081 | dead_assignment_remover::visit_assignment (assignment* e) | |
3082 | { | |
8b095b45 JS |
3083 | replace (e->left); |
3084 | replace (e->right); | |
8bda6498 | 3085 | |
bd70b999 JS |
3086 | symbol* left = get_assignment_symbol_within_expression (e->left); |
3087 | if (left) // not unresolved $target, so intended sideeffect may be elided | |
cbfbbf69 | 3088 | { |
bd70b999 | 3089 | vardecl* leftvar = left->referent; |
cbfbbf69 FCE |
3090 | if (vut.read.find(leftvar) == vut.read.end()) // var never read? |
3091 | { | |
cf9ff341 FCE |
3092 | // NB: Not so fast! The left side could be an array whose |
3093 | // index expressions may have side-effects. This would be | |
57148ee7 | 3094 | // OK if we could replace the array assignment with a |
cf9ff341 FCE |
3095 | // statement-expression containing all the index expressions |
3096 | // and the rvalue... but we can't. | |
0a102c82 SC |
3097 | // Another possibility is that we have an unread global variable |
3098 | // which are kept for probe end value display. | |
3099 | ||
3100 | bool is_global = false; | |
3101 | vector<vardecl*>::iterator it; | |
3102 | for (it = session.globals.begin(); it != session.globals.end(); it++) | |
3103 | if (leftvar->name == (*it)->name) | |
3104 | { | |
3105 | is_global = true; | |
3106 | break; | |
3107 | } | |
cf9ff341 | 3108 | |
313db8e6 | 3109 | varuse_collecting_visitor lvut(session); |
8bda6498 | 3110 | e->left->visit (& lvut); |
df16cbea | 3111 | if (lvut.side_effect_free () && !is_global // XXX: use _wrt() once we track focal_vars |
69aa668e | 3112 | && !leftvar->synthetic) // don't elide assignment to synthetic $context variables |
cf9ff341 | 3113 | { |
a9e8f7e0 FCE |
3114 | /* PR 1119: NB: This is not necessary here. A write-only |
3115 | variable will also be elided soon at the next _opt2 iteration. | |
bad814e8 CM |
3116 | if (e->left->tok->location.file->name == session.user_file->name) // !tapset |
3117 | session.print_warning("eliding write-only ", *e->left->tok); | |
a9e8f7e0 FCE |
3118 | else |
3119 | */ | |
ba48c27a | 3120 | if (session.is_user_file(e->left->tok->location.file->name)) |
7371cd19 | 3121 | session.print_warning(_F("Eliding assignment to '%s'", |
5eb6ecb1 | 3122 | leftvar->unmangled_name.to_string().c_str()), e->tok); |
8bda6498 | 3123 | provide (e->right); // goodbye assignment* |
cf9ff341 | 3124 | relaxed_p = false; |
8bda6498 | 3125 | return; |
cf9ff341 | 3126 | } |
cbfbbf69 FCE |
3127 | } |
3128 | } | |
8bda6498 | 3129 | provide (e); |
e7625481 | 3130 | } |
cbfbbf69 | 3131 | |
f4fe2e93 FCE |
3132 | |
3133 | void | |
3134 | dead_assignment_remover::visit_try_block (try_block *s) | |
3135 | { | |
3136 | replace (s->try_block); | |
3137 | if (s->catch_error_var) | |
3138 | { | |
3139 | vardecl* errvar = s->catch_error_var->referent; | |
3140 | if (vut.read.find(errvar) == vut.read.end()) // never read? | |
3141 | { | |
3142 | if (session.verbose>2) | |
4af765b2 | 3143 | clog << _F("Eliding unused error string catcher %s at %s", |
5eb6ecb1 DS |
3144 | errvar->unmangled_name.to_string().c_str(), |
3145 | lex_cast(*s->tok).c_str()) << endl; | |
f4fe2e93 FCE |
3146 | s->catch_error_var = 0; |
3147 | } | |
3148 | } | |
3149 | replace (s->catch_block); | |
3150 | provide (s); | |
3151 | } | |
3152 | ||
3153 | ||
cbfbbf69 FCE |
3154 | // Let's remove assignments to variables that are never read. We |
3155 | // rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to | |
3156 | // be optimized away as an unused variable, and expr a candidate to be | |
3157 | // removed as a side-effect-free statement expression. Wahoo! | |
3158 | void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p) | |
3159 | { | |
3160 | // Recompute the varuse data, which will probably match the opt2 | |
3161 | // copy of the computation, except for those totally unused | |
3162 | // variables that opt2 removed. | |
313db8e6 | 3163 | varuse_collecting_visitor vut(s); |
cbfbbf69 FCE |
3164 | for (unsigned i=0; i<s.probes.size(); i++) |
3165 | s.probes[i]->body->visit (& vut); // includes reachable functions too | |
3166 | ||
3167 | dead_assignment_remover dar (s, relaxed_p, vut); | |
3168 | // This instance may be reused for multiple probe/function body trims. | |
3169 | ||
3170 | for (unsigned i=0; i<s.probes.size(); i++) | |
8b095b45 | 3171 | dar.replace (s.probes[i]->body); |
8bda6498 JS |
3172 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); |
3173 | it != s.functions.end(); it++) | |
8b095b45 | 3174 | dar.replace (it->second->body); |
cbfbbf69 | 3175 | // The rewrite operation is performed within the visitor. |
27d24ae2 FCE |
3176 | |
3177 | // XXX: we could also zap write-only globals here | |
cbfbbf69 FCE |
3178 | } |
3179 | ||
3180 | ||
3181 | // ------------------------------------------------------------------------ | |
3182 | ||
1cd151d5 | 3183 | struct dead_stmtexpr_remover: public update_visitor |
cbfbbf69 FCE |
3184 | { |
3185 | systemtap_session& session; | |
3186 | bool& relaxed_p; | |
1b07c728 | 3187 | set<vardecl*> focal_vars; // vars considered subject to side-effects |
cbfbbf69 | 3188 | |
57148ee7 | 3189 | dead_stmtexpr_remover(systemtap_session& s, bool& r): |
1cd151d5 | 3190 | session(s), relaxed_p(r) {} |
cbfbbf69 FCE |
3191 | |
3192 | void visit_block (block *s); | |
f4fe2e93 | 3193 | void visit_try_block (try_block *s); |
ba6f838d | 3194 | void visit_null_statement (null_statement *s); |
739a3e81 FCE |
3195 | void visit_if_statement (if_statement* s); |
3196 | void visit_foreach_loop (foreach_loop *s); | |
3197 | void visit_for_loop (for_loop *s); | |
cbfbbf69 FCE |
3198 | // XXX: and other places where stmt_expr's might be nested |
3199 | ||
3200 | void visit_expr_statement (expr_statement *s); | |
3201 | }; | |
3202 | ||
3203 | ||
ba6f838d FCE |
3204 | void |
3205 | dead_stmtexpr_remover::visit_null_statement (null_statement *s) | |
3206 | { | |
3207 | // easy! | |
3208 | if (session.verbose>2) | |
4af765b2 | 3209 | clog << _("Eliding side-effect-free null statement ") << *s->tok << endl; |
1cd151d5 JS |
3210 | s = 0; |
3211 | provide (s); | |
ba6f838d FCE |
3212 | } |
3213 | ||
3214 | ||
cbfbbf69 FCE |
3215 | void |
3216 | dead_stmtexpr_remover::visit_block (block *s) | |
3217 | { | |
ba6f838d FCE |
3218 | vector<statement*> new_stmts; |
3219 | for (unsigned i=0; i<s->statements.size(); i++ ) | |
cbfbbf69 | 3220 | { |
1cd151d5 JS |
3221 | statement* new_stmt = require (s->statements[i], true); |
3222 | if (new_stmt != 0) | |
bea72737 JS |
3223 | { |
3224 | // flatten nested blocks into this one | |
1cd151d5 | 3225 | block *b = dynamic_cast<block *>(new_stmt); |
bea72737 JS |
3226 | if (b) |
3227 | { | |
3228 | if (session.verbose>2) | |
4af765b2 | 3229 | clog << _("Flattening nested block ") << *b->tok << endl; |
bea72737 JS |
3230 | new_stmts.insert(new_stmts.end(), |
3231 | b->statements.begin(), b->statements.end()); | |
3232 | relaxed_p = false; | |
3233 | } | |
3234 | else | |
1cd151d5 | 3235 | new_stmts.push_back (new_stmt); |
bea72737 | 3236 | } |
cbfbbf69 | 3237 | } |
ba6f838d FCE |
3238 | if (new_stmts.size() == 0) |
3239 | { | |
3240 | if (session.verbose>2) | |
4af765b2 | 3241 | clog << _("Eliding side-effect-free empty block ") << *s->tok << endl; |
1cd151d5 | 3242 | s = 0; |
ba6f838d FCE |
3243 | } |
3244 | else if (new_stmts.size() == 1) | |
3245 | { | |
3246 | if (session.verbose>2) | |
4af765b2 | 3247 | clog << _("Eliding side-effect-free singleton block ") << *s->tok << endl; |
1cd151d5 JS |
3248 | provide (new_stmts[0]); |
3249 | return; | |
ba6f838d FCE |
3250 | } |
3251 | else | |
1cd151d5 JS |
3252 | s->statements = new_stmts; |
3253 | provide (s); | |
cbfbbf69 FCE |
3254 | } |
3255 | ||
f4fe2e93 FCE |
3256 | |
3257 | void | |
3258 | dead_stmtexpr_remover::visit_try_block (try_block *s) | |
3259 | { | |
3260 | replace (s->try_block, true); | |
3261 | replace (s->catch_block, true); // null catch{} is ok and useful | |
3262 | if (s->try_block == 0) | |
3263 | { | |
3264 | if (session.verbose>2) | |
4af765b2 | 3265 | clog << _("Eliding empty try {} block ") << *s->tok << endl; |
f4fe2e93 FCE |
3266 | s = 0; |
3267 | } | |
3268 | provide (s); | |
3269 | } | |
3270 | ||
3271 | ||
739a3e81 FCE |
3272 | void |
3273 | dead_stmtexpr_remover::visit_if_statement (if_statement *s) | |
3274 | { | |
8b095b45 JS |
3275 | replace (s->thenblock, true); |
3276 | replace (s->elseblock, true); | |
ba6f838d | 3277 | |
bea72737 | 3278 | if (s->thenblock == 0) |
ba6f838d | 3279 | { |
bea72737 JS |
3280 | if (s->elseblock == 0) |
3281 | { | |
3282 | // We may be able to elide this statement, if the condition | |
3283 | // expression is side-effect-free. | |
313db8e6 | 3284 | varuse_collecting_visitor vct(session); |
bea72737 JS |
3285 | s->condition->visit(& vct); |
3286 | if (vct.side_effect_free ()) | |
3287 | { | |
3288 | if (session.verbose>2) | |
4af765b2 | 3289 | clog << _("Eliding side-effect-free if statement ") |
bea72737 | 3290 | << *s->tok << endl; |
1cd151d5 | 3291 | s = 0; // yeah, baby |
bea72737 JS |
3292 | } |
3293 | else | |
3294 | { | |
3295 | // We can still turn it into a simple expr_statement though... | |
3296 | if (session.verbose>2) | |
4af765b2 | 3297 | clog << _("Creating simple evaluation from if statement ") |
bea72737 JS |
3298 | << *s->tok << endl; |
3299 | expr_statement *es = new expr_statement; | |
3300 | es->value = s->condition; | |
3301 | es->tok = es->value->tok; | |
1cd151d5 JS |
3302 | provide (es); |
3303 | return; | |
bea72737 JS |
3304 | } |
3305 | } | |
3306 | else | |
ba6f838d | 3307 | { |
bea72737 JS |
3308 | // For an else without a then, we can invert the condition logic to |
3309 | // avoid having a null statement in the thenblock | |
ba6f838d | 3310 | if (session.verbose>2) |
4af765b2 | 3311 | clog << _("Inverting the condition of if statement ") |
bea72737 JS |
3312 | << *s->tok << endl; |
3313 | unary_expression *ue = new unary_expression; | |
3314 | ue->operand = s->condition; | |
3315 | ue->tok = ue->operand->tok; | |
3316 | ue->op = "!"; | |
3317 | s->condition = ue; | |
3318 | s->thenblock = s->elseblock; | |
3319 | s->elseblock = 0; | |
ba6f838d FCE |
3320 | } |
3321 | } | |
1cd151d5 | 3322 | provide (s); |
739a3e81 FCE |
3323 | } |
3324 | ||
3325 | void | |
3326 | dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s) | |
3327 | { | |
8b095b45 | 3328 | replace (s->block, true); |
ba6f838d FCE |
3329 | |
3330 | if (s->block == 0) | |
3331 | { | |
10328bcf | 3332 | // XXX what if s->limit has side effects? |
c261711d | 3333 | // XXX what about s->indexes or s->value used outside the loop? |
bad814e8 | 3334 | if(session.verbose > 2) |
4af765b2 | 3335 | clog << _("Eliding side-effect-free foreach statement ") << *s->tok << endl; |
1cd151d5 | 3336 | s = 0; // yeah, baby |
ba6f838d | 3337 | } |
1cd151d5 | 3338 | provide (s); |
739a3e81 FCE |
3339 | } |
3340 | ||
3341 | void | |
3342 | dead_stmtexpr_remover::visit_for_loop (for_loop *s) | |
3343 | { | |
8b095b45 | 3344 | replace (s->block, true); |
ba6f838d FCE |
3345 | |
3346 | if (s->block == 0) | |
3347 | { | |
3348 | // We may be able to elide this statement, if the condition | |
3349 | // expression is side-effect-free. | |
313db8e6 | 3350 | varuse_collecting_visitor vct(session); |
ba6f838d FCE |
3351 | if (s->init) s->init->visit(& vct); |
3352 | s->cond->visit(& vct); | |
3353 | if (s->incr) s->incr->visit(& vct); | |
3354 | if (vct.side_effect_free ()) | |
3355 | { | |
3356 | if (session.verbose>2) | |
4af765b2 | 3357 | clog << _("Eliding side-effect-free for statement ") << *s->tok << endl; |
1cd151d5 JS |
3358 | s = 0; // yeah, baby |
3359 | } | |
3360 | else | |
3361 | { | |
3362 | // Can't elide this whole statement; put a null in there. | |
f946b10f | 3363 | s->block = new null_statement(s->tok); |
ba6f838d | 3364 | } |
ba6f838d | 3365 | } |
1cd151d5 | 3366 | provide (s); |
739a3e81 FCE |
3367 | } |
3368 | ||
3369 | ||
cbfbbf69 FCE |
3370 | |
3371 | void | |
3372 | dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) | |
3373 | { | |
3374 | // Run a varuse query against the operand expression. If it has no | |
3375 | // side-effects, replace the entire statement expression by a null | |
1cd151d5 | 3376 | // statement with the provide() call. |
cbfbbf69 FCE |
3377 | // |
3378 | // Unlike many other visitors, we do *not* traverse this outermost | |
3379 | // one into the expression subtrees. There is no need - no | |
3380 | // expr_statement nodes will be found there. (Function bodies | |
3381 | // need to be visited explicitly by our caller.) | |
3382 | // | |
3383 | // NB. While we don't share nodes in the parse tree, let's not | |
3384 | // deallocate *s anyway, just in case... | |
3385 | ||
313db8e6 | 3386 | varuse_collecting_visitor vut(session); |
cbfbbf69 | 3387 | s->value->visit (& vut); |
57148ee7 | 3388 | |
1cd151d5 | 3389 | if (vut.side_effect_free_wrt (focal_vars)) |
cbfbbf69 | 3390 | { |
a9e8f7e0 FCE |
3391 | /* PR 1119: NB: this message is not a good idea here. It can |
3392 | name some arbitrary RHS expression of an assignment. | |
bad814e8 CM |
3393 | if (s->value->tok->location.file->name == session.user_file->name) // not tapset |
3394 | session.print_warning("eliding never-assigned ", *s->value->tok); | |
57148ee7 | 3395 | else |
a9e8f7e0 | 3396 | */ |
ba48c27a | 3397 | if (session.is_user_file(s->value->tok->location.file->name)) |
bad814e8 | 3398 | session.print_warning("Eliding side-effect-free expression ", s->tok); |
cbfbbf69 | 3399 | |
ba6f838d FCE |
3400 | // NB: this 0 pointer is invalid to leave around for any length of |
3401 | // time, but the parent parse tree objects above handle it. | |
1cd151d5 | 3402 | s = 0; |
cbfbbf69 FCE |
3403 | relaxed_p = false; |
3404 | } | |
1cd151d5 | 3405 | provide (s); |
cbfbbf69 FCE |
3406 | } |
3407 | ||
3408 | ||
3409 | void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) | |
3410 | { | |
3411 | // Finally, let's remove some statement-expressions that have no | |
3412 | // side-effect. These should be exactly those whose private varuse | |
3413 | // visitors come back with an empty "written" and "embedded" lists. | |
57148ee7 | 3414 | |
cbfbbf69 FCE |
3415 | dead_stmtexpr_remover duv (s, relaxed_p); |
3416 | // This instance may be reused for multiple probe/function body trims. | |
3417 | ||
3418 | for (unsigned i=0; i<s.probes.size(); i++) | |
1b07c728 | 3419 | { |
e19ebcf7 | 3420 | assert_no_interrupts(); |
f76427a2 | 3421 | |
ba6f838d FCE |
3422 | derived_probe* p = s.probes[i]; |
3423 | ||
1b07c728 FCE |
3424 | duv.focal_vars.clear (); |
3425 | duv.focal_vars.insert (s.globals.begin(), | |
3426 | s.globals.end()); | |
ba6f838d FCE |
3427 | duv.focal_vars.insert (p->locals.begin(), |
3428 | p->locals.end()); | |
3429 | ||
8b095b45 | 3430 | duv.replace (p->body, true); |
ba6f838d FCE |
3431 | if (p->body == 0) |
3432 | { | |
f161bd74 JL |
3433 | if (! s.timing && // PR10070 |
3434 | !(p->base->tok->location.file->synthetic)) // don't warn for synthetic probes | |
7371cd19 | 3435 | s.print_warning (_F("side-effect-free probe '%s'", |
1341a03c | 3436 | p->name().c_str()), p->tok); |
ba6f838d | 3437 | |
f946b10f | 3438 | p->body = new null_statement(p->tok); |
27d24ae2 FCE |
3439 | |
3440 | // XXX: possible duplicate warnings; see below | |
ba6f838d | 3441 | } |
1b07c728 | 3442 | } |
f76427a2 | 3443 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
1b07c728 | 3444 | { |
e19ebcf7 | 3445 | assert_no_interrupts(); |
f76427a2 FCE |
3446 | |
3447 | functiondecl* fn = it->second; | |
1b07c728 | 3448 | duv.focal_vars.clear (); |
ba6f838d FCE |
3449 | duv.focal_vars.insert (fn->locals.begin(), |
3450 | fn->locals.end()); | |
3451 | duv.focal_vars.insert (fn->formal_args.begin(), | |
3452 | fn->formal_args.end()); | |
1b07c728 FCE |
3453 | duv.focal_vars.insert (s.globals.begin(), |
3454 | s.globals.end()); | |
ba6f838d | 3455 | |
8b095b45 | 3456 | duv.replace (fn->body, true); |
ba6f838d FCE |
3457 | if (fn->body == 0) |
3458 | { | |
7371cd19 | 3459 | s.print_warning (_F("side-effect-free function '%s'", |
5eb6ecb1 DS |
3460 | fn->unmangled_name.to_string().c_str()), |
3461 | fn->tok); | |
ba6f838d | 3462 | |
f946b10f | 3463 | fn->body = new null_statement(fn->tok); |
27d24ae2 FCE |
3464 | |
3465 | // XXX: the next iteration of the outer optimization loop may | |
3466 | // take this new null_statement away again, and thus give us a | |
3467 | // fresh warning. It would be better if this fixup was performed | |
3468 | // only after the relaxation iterations. | |
3469 | // XXX: or else see bug #6469. | |
ba6f838d | 3470 | } |
1b07c728 | 3471 | } |
cbfbbf69 FCE |
3472 | } |
3473 | ||
bea72737 JS |
3474 | |
3475 | // ------------------------------------------------------------------------ | |
3476 | ||
3477 | // The goal of this visitor is to reduce top-level expressions in void context | |
3478 | // into separate statements that evaluate each subcomponent of the expression. | |
3479 | // The dead-statement-remover can later remove some parts if they have no side | |
3480 | // effects. | |
9f9873df JS |
3481 | // |
3482 | // All expressions must be overridden here so we never visit their subexpressions | |
3483 | // accidentally. Thus, the only visited expressions should be value of an | |
3484 | // expr_statement. | |
3485 | // | |
3486 | // For an expression to replace its expr_statement with something else, it will | |
3487 | // let the new statement provide(), and then provide(0) for itself. The | |
3488 | // expr_statement will take this as a sign that it's been replaced. | |
3489 | struct void_statement_reducer: public update_visitor | |
bea72737 JS |
3490 | { |
3491 | systemtap_session& session; | |
3492 | bool& relaxed_p; | |
bea72737 JS |
3493 | set<vardecl*> focal_vars; // vars considered subject to side-effects |
3494 | ||
3495 | void_statement_reducer(systemtap_session& s, bool& r): | |
9f9873df | 3496 | session(s), relaxed_p(r) {} |
bea72737 | 3497 | |
133c7b1d | 3498 | void visit_expr_statement (expr_statement* s); |
9f9873df JS |
3499 | |
3500 | // expressions in conditional / loop controls are definitely a side effect, | |
3501 | // but still recurse into the child statements | |
bea72737 JS |
3502 | void visit_if_statement (if_statement* s); |
3503 | void visit_for_loop (for_loop* s); | |
3504 | void visit_foreach_loop (foreach_loop* s); | |
3505 | ||
3506 | // these expressions get rewritten into their statement equivalents | |
3507 | void visit_logical_or_expr (logical_or_expr* e); | |
3508 | void visit_logical_and_expr (logical_and_expr* e); | |
3509 | void visit_ternary_expression (ternary_expression* e); | |
3510 | ||
93daaca8 | 3511 | // all of these can (usually) be reduced into simpler statements |
bea72737 JS |
3512 | void visit_binary_expression (binary_expression* e); |
3513 | void visit_unary_expression (unary_expression* e); | |
ac01386b | 3514 | void visit_regex_query (regex_query* e); // XXX depends on subexpr extraction |
bea72737 JS |
3515 | void visit_comparison (comparison* e); |
3516 | void visit_concatenation (concatenation* e); | |
3517 | void visit_functioncall (functioncall* e); | |
3518 | void visit_print_format (print_format* e); | |
6fda2dff | 3519 | void visit_target_symbol (target_symbol* e); |
bd1fcbad | 3520 | void visit_atvar_op (atvar_op* e); |
9b5af295 | 3521 | void visit_cast_op (cast_op* e); |
251707c8 | 3522 | void visit_autocast_op (autocast_op* e); |
30263a73 | 3523 | void visit_defined_op (defined_op* e); |
bea72737 JS |
3524 | |
3525 | // these are a bit hairy to grok due to the intricacies of indexables and | |
3526 | // stats, so I'm chickening out and skipping them... | |
9f9873df JS |
3527 | void visit_array_in (array_in* e) { provide (e); } |
3528 | void visit_arrayindex (arrayindex* e) { provide (e); } | |
3529 | void visit_stat_op (stat_op* e) { provide (e); } | |
3530 | void visit_hist_op (hist_op* e) { provide (e); } | |
bea72737 JS |
3531 | |
3532 | // these can't be reduced because they always have an effect | |
9f9873df JS |
3533 | void visit_return_statement (return_statement* s) { provide (s); } |
3534 | void visit_delete_statement (delete_statement* s) { provide (s); } | |
3535 | void visit_pre_crement (pre_crement* e) { provide (e); } | |
3536 | void visit_post_crement (post_crement* e) { provide (e); } | |
3537 | void visit_assignment (assignment* e) { provide (e); } | |
251707c8 JS |
3538 | |
3539 | private: | |
3540 | void reduce_target_symbol (target_symbol* e, expression* operand=NULL); | |
bea72737 JS |
3541 | }; |
3542 | ||
3543 | ||
133c7b1d JS |
3544 | void |
3545 | void_statement_reducer::visit_expr_statement (expr_statement* s) | |
3546 | { | |
8b095b45 | 3547 | replace (s->value, true); |
133c7b1d | 3548 | |
9f9873df JS |
3549 | // if the expression provides 0, that's our signal that a new |
3550 | // statement has been provided, so we shouldn't provide this one. | |
3551 | if (s->value != 0) | |
3552 | provide(s); | |
bea72737 JS |
3553 | } |
3554 | ||
3555 | void | |
3556 | void_statement_reducer::visit_if_statement (if_statement* s) | |
3557 | { | |
9f9873df | 3558 | // s->condition is never void |
8b095b45 JS |
3559 | replace (s->thenblock); |
3560 | replace (s->elseblock); | |
9f9873df | 3561 | provide (s); |
bea72737 JS |
3562 | } |
3563 | ||
3564 | void | |
3565 | void_statement_reducer::visit_for_loop (for_loop* s) | |
3566 | { | |
9f9873df | 3567 | // s->init/cond/incr are never void |
8b095b45 | 3568 | replace (s->block); |
9f9873df | 3569 | provide (s); |
bea72737 JS |
3570 | } |
3571 | ||
3572 | void | |
3573 | void_statement_reducer::visit_foreach_loop (foreach_loop* s) | |
3574 | { | |
c261711d | 3575 | // s->indexes/base/value/limit are never void |
8b095b45 | 3576 | replace (s->block); |
9f9873df | 3577 | provide (s); |
bea72737 JS |
3578 | } |
3579 | ||
3580 | void | |
3581 | void_statement_reducer::visit_logical_or_expr (logical_or_expr* e) | |
3582 | { | |
3583 | // In void context, the evaluation of "a || b" is exactly like | |
3584 | // "if (!a) b", so let's do that instead. | |
3585 | ||
bea72737 | 3586 | if (session.verbose>2) |
4af765b2 | 3587 | clog << _("Creating if statement from unused logical-or ") |
bea72737 JS |
3588 | << *e->tok << endl; |
3589 | ||
3590 | if_statement *is = new if_statement; | |
3591 | is->tok = e->tok; | |
3592 | is->elseblock = 0; | |
bea72737 JS |
3593 | |
3594 | unary_expression *ue = new unary_expression; | |
3595 | ue->operand = e->left; | |
3596 | ue->tok = e->tok; | |
3597 | ue->op = "!"; | |
3598 | is->condition = ue; | |
3599 | ||
133c7b1d | 3600 | expr_statement *es = new expr_statement; |
bea72737 JS |
3601 | es->value = e->right; |
3602 | es->tok = es->value->tok; | |
3603 | is->thenblock = es; | |
3604 | ||
3605 | is->visit(this); | |
3606 | relaxed_p = false; | |
9f9873df JS |
3607 | e = 0; |
3608 | provide (e); | |
bea72737 JS |
3609 | } |
3610 | ||
3611 | void | |
3612 | void_statement_reducer::visit_logical_and_expr (logical_and_expr* e) | |
3613 | { | |
3614 | // In void context, the evaluation of "a && b" is exactly like | |
3615 | // "if (a) b", so let's do that instead. | |
3616 | ||
bea72737 | 3617 | if (session.verbose>2) |
4af765b2 | 3618 | clog << _("Creating if statement from unused logical-and ") |
bea72737 JS |
3619 | << *e->tok << endl; |
3620 | ||
3621 | if_statement *is = new if_statement; | |
3622 | is->tok = e->tok; | |
3623 | is->elseblock = 0; | |
3624 | is->condition = e->left; | |
bea72737 | 3625 | |
133c7b1d | 3626 | expr_statement *es = new expr_statement; |
bea72737 JS |
3627 | es->value = e->right; |
3628 | es->tok = es->value->tok; | |
3629 | is->thenblock = es; | |
3630 | ||
3631 | is->visit(this); | |
3632 | relaxed_p = false; | |
9f9873df JS |
3633 | e = 0; |
3634 | provide (e); | |
bea72737 JS |
3635 | } |
3636 | ||
3637 | void | |
3638 | void_statement_reducer::visit_ternary_expression (ternary_expression* e) | |
3639 | { | |
3640 | // In void context, the evaluation of "a ? b : c" is exactly like | |
3641 | // "if (a) b else c", so let's do that instead. | |
3642 | ||
bea72737 | 3643 | if (session.verbose>2) |
4af765b2 | 3644 | clog << _("Creating if statement from unused ternary expression ") |
bea72737 JS |
3645 | << *e->tok << endl; |
3646 | ||
3647 | if_statement *is = new if_statement; | |
3648 | is->tok = e->tok; | |
3649 | is->condition = e->cond; | |
bea72737 | 3650 | |
133c7b1d | 3651 | expr_statement *es = new expr_statement; |
bea72737 JS |
3652 | es->value = e->truevalue; |
3653 | es->tok = es->value->tok; | |
3654 | is->thenblock = es; | |
3655 | ||
3656 | es = new expr_statement; | |
3657 | es->value = e->falsevalue; | |
3658 | es->tok = es->value->tok; | |
3659 | is->elseblock = es; | |
3660 | ||
3661 | is->visit(this); | |
3662 | relaxed_p = false; | |
9f9873df JS |
3663 | e = 0; |
3664 | provide (e); | |
bea72737 JS |
3665 | } |
3666 | ||
3667 | void | |
3668 | void_statement_reducer::visit_binary_expression (binary_expression* e) | |
3669 | { | |
3670 | // When the result of a binary operation isn't needed, it's just as good to | |
3671 | // evaluate the operands as sequential statements in a block. | |
3672 | ||
bea72737 | 3673 | if (session.verbose>2) |
4af765b2 | 3674 | clog << _("Eliding unused binary ") << *e->tok << endl; |
bea72737 JS |
3675 | |
3676 | block *b = new block; | |
9f9873df | 3677 | b->tok = e->tok; |
bea72737 | 3678 | |
133c7b1d | 3679 | expr_statement *es = new expr_statement; |
bea72737 JS |
3680 | es->value = e->left; |
3681 | es->tok = es->value->tok; | |
3682 | b->statements.push_back(es); | |
3683 | ||
3684 | es = new expr_statement; | |
3685 | es->value = e->right; | |
3686 | es->tok = es->value->tok; | |
3687 | b->statements.push_back(es); | |
3688 | ||
3689 | b->visit(this); | |
3690 | relaxed_p = false; | |
9f9873df JS |
3691 | e = 0; |
3692 | provide (e); | |
bea72737 JS |
3693 | } |
3694 | ||
3695 | void | |
3696 | void_statement_reducer::visit_unary_expression (unary_expression* e) | |
3697 | { | |
3698 | // When the result of a unary operation isn't needed, it's just as good to | |
3699 | // evaluate the operand directly | |
3700 | ||
bea72737 | 3701 | if (session.verbose>2) |
4af765b2 | 3702 | clog << _("Eliding unused unary ") << *e->tok << endl; |
bea72737 | 3703 | |
bea72737 | 3704 | relaxed_p = false; |
9f9873df | 3705 | e->operand->visit(this); |
bea72737 JS |
3706 | } |
3707 | ||
93daaca8 SM |
3708 | void |
3709 | void_statement_reducer::visit_regex_query (regex_query* e) | |
3710 | { | |
ac01386b SM |
3711 | // TODOXXX After subexpression extraction is implemented, |
3712 | // regular expression matches *may* have side-effects in | |
3713 | // terms of producing matched subexpressions, e.g.: | |
93daaca8 | 3714 | // |
ac01386b SM |
3715 | // str =~ "pat"; println(matched(0)); |
3716 | // | |
3717 | // It's debatable if we want to actually allow this, though. | |
93daaca8 | 3718 | |
ac01386b SM |
3719 | // Treat e as a unary expression on the left operand -- since the |
3720 | // right hand side must be a literal (as verified by the parser), | |
93daaca8 SM |
3721 | // evaluating it never has side effects. |
3722 | ||
3723 | if (session.verbose>2) | |
3724 | clog << _("Eliding regex query ") << *e->tok << endl; | |
3725 | ||
3726 | relaxed_p = false; | |
3727 | e->left->visit(this); | |
3728 | } | |
3729 | ||
bea72737 JS |
3730 | void |
3731 | void_statement_reducer::visit_comparison (comparison* e) | |
3732 | { | |
3733 | visit_binary_expression(e); | |
3734 | } | |
3735 | ||
3736 | void | |
3737 | void_statement_reducer::visit_concatenation (concatenation* e) | |
3738 | { | |
3739 | visit_binary_expression(e); | |
3740 | } | |
3741 | ||
3742 | void | |
3743 | void_statement_reducer::visit_functioncall (functioncall* e) | |
3744 | { | |
3745 | // If a function call is pure and its result ignored, we can elide the call | |
c7d47935 | 3746 | // and just evaluate the arguments in sequence |
bea72737 | 3747 | |
7b5b30a8 | 3748 | if (e->args.empty()) |
9f9873df JS |
3749 | { |
3750 | provide (e); | |
3751 | return; | |
3752 | } | |
bea72737 | 3753 | |
7b5b30a8 FL |
3754 | bool side_effect_free = true; |
3755 | for (unsigned i = 0; i < e->referents.size(); i++) | |
3756 | { | |
3757 | varuse_collecting_visitor vut(session); | |
3758 | vut.seen.insert (e->referents[i]); | |
3759 | vut.current_function = e->referents[i]; | |
3760 | e->referents[i]->body->visit (& vut); | |
3761 | if (!vut.side_effect_free_wrt(focal_vars)) | |
3762 | { | |
3763 | side_effect_free = false; | |
3764 | break; | |
3765 | } | |
3766 | } | |
3767 | ||
3768 | if (!side_effect_free) | |
9f9873df JS |
3769 | { |
3770 | provide (e); | |
3771 | return; | |
3772 | } | |
bea72737 JS |
3773 | |
3774 | if (session.verbose>2) | |
4af765b2 | 3775 | clog << _("Eliding side-effect-free function call ") << *e->tok << endl; |
bea72737 | 3776 | |
133c7b1d JS |
3777 | block *b = new block; |
3778 | b->tok = e->tok; | |
bea72737 | 3779 | |
133c7b1d | 3780 | for (unsigned i=0; i<e->args.size(); i++ ) |
bea72737 | 3781 | { |
133c7b1d JS |
3782 | expr_statement *es = new expr_statement; |
3783 | es->value = e->args[i]; | |
3784 | es->tok = es->value->tok; | |
bea72737 | 3785 | b->statements.push_back(es); |
bea72737 JS |
3786 | } |
3787 | ||
133c7b1d | 3788 | b->visit(this); |
bea72737 | 3789 | relaxed_p = false; |
9f9873df JS |
3790 | e = 0; |
3791 | provide (e); | |
bea72737 JS |
3792 | } |
3793 | ||
3794 | void | |
3795 | void_statement_reducer::visit_print_format (print_format* e) | |
3796 | { | |
3797 | // When an sprint's return value is ignored, we can simply evaluate the | |
3798 | // arguments in sequence | |
3799 | ||
3800 | if (e->print_to_stream || !e->args.size()) | |
9f9873df JS |
3801 | { |
3802 | provide (e); | |
3803 | return; | |
3804 | } | |
bea72737 JS |
3805 | |
3806 | if (session.verbose>2) | |
4af765b2 | 3807 | clog << _("Eliding unused print ") << *e->tok << endl; |
bea72737 | 3808 | |
133c7b1d JS |
3809 | block *b = new block; |
3810 | b->tok = e->tok; | |
bea72737 | 3811 | |
133c7b1d | 3812 | for (unsigned i=0; i<e->args.size(); i++ ) |
bea72737 | 3813 | { |
133c7b1d JS |
3814 | expr_statement *es = new expr_statement; |
3815 | es->value = e->args[i]; | |
3816 | es->tok = es->value->tok; | |
bea72737 | 3817 | b->statements.push_back(es); |
bea72737 JS |
3818 | } |
3819 | ||
133c7b1d | 3820 | b->visit(this); |
bea72737 | 3821 | relaxed_p = false; |
9f9873df JS |
3822 | e = 0; |
3823 | provide (e); | |
bea72737 JS |
3824 | } |
3825 | ||
bd1fcbad | 3826 | void |
251707c8 JS |
3827 | void_statement_reducer::reduce_target_symbol (target_symbol* e, |
3828 | expression* operand) | |
bd1fcbad | 3829 | { |
251707c8 JS |
3830 | // When the result of any target_symbol isn't needed, it's just as good to |
3831 | // evaluate the operand and any array indexes directly | |
6fda2dff JS |
3832 | |
3833 | block *b = new block; | |
3834 | b->tok = e->tok; | |
3835 | ||
251707c8 JS |
3836 | if (operand) |
3837 | { | |
3838 | expr_statement *es = new expr_statement; | |
3839 | es->value = operand; | |
3840 | es->tok = es->value->tok; | |
3841 | b->statements.push_back(es); | |
3842 | } | |
3843 | ||
6fda2dff JS |
3844 | for (unsigned i=0; i<e->components.size(); i++ ) |
3845 | { | |
3846 | if (e->components[i].type != target_symbol::comp_expression_array_index) | |
3847 | continue; | |
3848 | ||
3849 | expr_statement *es = new expr_statement; | |
3850 | es->value = e->components[i].expr_index; | |
3851 | es->tok = es->value->tok; | |
3852 | b->statements.push_back(es); | |
3853 | } | |
3854 | ||
6fda2dff JS |
3855 | b->visit(this); |
3856 | relaxed_p = false; | |
3857 | e = 0; | |
3858 | provide (e); | |
3859 | } | |
3860 | ||
9b5af295 | 3861 | void |
251707c8 | 3862 | void_statement_reducer::visit_atvar_op (atvar_op* e) |
9b5af295 | 3863 | { |
251707c8 JS |
3864 | if (session.verbose>2) |
3865 | clog << _("Eliding unused target symbol ") << *e->tok << endl; | |
3866 | reduce_target_symbol (e); | |
3867 | } | |
6fda2dff | 3868 | |
251707c8 JS |
3869 | void |
3870 | void_statement_reducer::visit_target_symbol (target_symbol* e) | |
3871 | { | |
3872 | if (session.verbose>2) | |
3873 | clog << _("Eliding unused target symbol ") << *e->tok << endl; | |
3874 | reduce_target_symbol (e); | |
3875 | } | |
9b5af295 | 3876 | |
251707c8 JS |
3877 | void |
3878 | void_statement_reducer::visit_cast_op (cast_op* e) | |
3879 | { | |
9b5af295 | 3880 | if (session.verbose>2) |
4af765b2 | 3881 | clog << _("Eliding unused typecast ") << *e->tok << endl; |
251707c8 JS |
3882 | reduce_target_symbol (e, e->operand); |
3883 | } | |
9b5af295 | 3884 | |
251707c8 JS |
3885 | void |
3886 | void_statement_reducer::visit_autocast_op (autocast_op* e) | |
3887 | { | |
3888 | if (session.verbose>2) | |
3889 | clog << _("Eliding unused autocast ") << *e->tok << endl; | |
3890 | reduce_target_symbol (e, e->operand); | |
9b5af295 JS |
3891 | } |
3892 | ||
bea72737 | 3893 | |
30263a73 FCE |
3894 | void |
3895 | void_statement_reducer::visit_defined_op (defined_op* e) | |
3896 | { | |
3897 | // When the result of a @defined operation isn't needed, just elide | |
3898 | // it entirely. Its operand $expression must already be | |
3899 | // side-effect-free. | |
3900 | ||
3901 | if (session.verbose>2) | |
4af765b2 | 3902 | clog << _("Eliding unused check ") << *e->tok << endl; |
30263a73 FCE |
3903 | |
3904 | relaxed_p = false; | |
3905 | e = 0; | |
3906 | provide (e); | |
3907 | } | |
3908 | ||
3909 | ||
3910 | ||
bea72737 JS |
3911 | void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) |
3912 | { | |
3913 | // Let's simplify statements with unused computed values. | |
3914 | ||
3915 | void_statement_reducer vuv (s, relaxed_p); | |
3916 | // This instance may be reused for multiple probe/function body trims. | |
3917 | ||
3918 | vuv.focal_vars.insert (s.globals.begin(), s.globals.end()); | |
3919 | ||
3920 | for (unsigned i=0; i<s.probes.size(); i++) | |
8b095b45 | 3921 | vuv.replace (s.probes[i]->body); |
9f9873df JS |
3922 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); |
3923 | it != s.functions.end(); it++) | |
8b095b45 | 3924 | vuv.replace (it->second->body); |
bea72737 JS |
3925 | } |
3926 | ||
3927 | ||
10328bcf JS |
3928 | struct const_folder: public update_visitor |
3929 | { | |
3930 | systemtap_session& session; | |
3931 | bool& relaxed_p; | |
3932 | ||
3933 | const_folder(systemtap_session& s, bool& r): | |
3934 | session(s), relaxed_p(r), last_number(0), last_string(0) {} | |
3935 | ||
3936 | literal_number* last_number; | |
3937 | literal_number* get_number(expression*& e); | |
3938 | void visit_literal_number (literal_number* e); | |
3939 | ||
3940 | literal_string* last_string; | |
3941 | literal_string* get_string(expression*& e); | |
3942 | void visit_literal_string (literal_string* e); | |
3943 | ||
f4869658 JS |
3944 | void get_literal(expression*& e, literal_number*& n, literal_string*& s); |
3945 | ||
10328bcf JS |
3946 | void visit_if_statement (if_statement* s); |
3947 | void visit_for_loop (for_loop* s); | |
3948 | void visit_foreach_loop (foreach_loop* s); | |
3949 | void visit_binary_expression (binary_expression* e); | |
3950 | void visit_unary_expression (unary_expression* e); | |
3951 | void visit_logical_or_expr (logical_or_expr* e); | |
3952 | void visit_logical_and_expr (logical_and_expr* e); | |
7a6ae283 | 3953 | // void visit_regex_query (regex_query* e); // XXX: would require executing dfa at compile-time |
10328bcf JS |
3954 | void visit_comparison (comparison* e); |
3955 | void visit_concatenation (concatenation* e); | |
3956 | void visit_ternary_expression (ternary_expression* e); | |
b7aedf26 | 3957 | void visit_defined_op (defined_op* e); |
9fab2262 | 3958 | void visit_target_symbol (target_symbol* e); |
10328bcf JS |
3959 | }; |
3960 | ||
f4869658 JS |
3961 | void |
3962 | const_folder::get_literal(expression*& e, | |
3963 | literal_number*& n, | |
3964 | literal_string*& s) | |
3965 | { | |
3966 | replace (e); | |
3967 | n = (e == last_number) ? last_number : NULL; | |
3968 | s = (e == last_string) ? last_string : NULL; | |
3969 | } | |
3970 | ||
10328bcf JS |
3971 | literal_number* |
3972 | const_folder::get_number(expression*& e) | |
3973 | { | |
3974 | replace (e); | |
3975 | return (e == last_number) ? last_number : NULL; | |
3976 | } | |
3977 | ||
3978 | void | |
3979 | const_folder::visit_literal_number (literal_number* e) | |
3980 | { | |
3981 | last_number = e; | |
3982 | provide (e); | |
3983 | } | |
3984 | ||
3985 | literal_string* | |
3986 | const_folder::get_string(expression*& e) | |
3987 | { | |
3988 | replace (e); | |
3989 | return (e == last_string) ? last_string : NULL; | |
3990 | } | |
3991 | ||
3992 | void | |
3993 | const_folder::visit_literal_string (literal_string* e) | |
3994 | { | |
3995 | last_string = e; | |
3996 | provide (e); | |
3997 | } | |
3998 | ||
3999 | void | |
4000 | const_folder::visit_if_statement (if_statement* s) | |
4001 | { | |
4002 | literal_number* cond = get_number (s->condition); | |
4003 | if (!cond) | |
4004 | { | |
4005 | replace (s->thenblock); | |
4006 | replace (s->elseblock); | |
4007 | provide (s); | |
4008 | } | |
4009 | else | |
4010 | { | |
4011 | if (session.verbose>2) | |
4af765b2 LB |
4012 | clog << _F("Collapsing constant-%" PRIi64 " if-statement %s", |
4013 | cond->value, lex_cast(*s->tok).c_str()) << endl; | |
10328bcf JS |
4014 | relaxed_p = false; |
4015 | ||
4016 | statement* n = cond->value ? s->thenblock : s->elseblock; | |
4017 | if (n) | |
4018 | n->visit (this); | |
4019 | else | |
4020 | provide (new null_statement (s->tok)); | |
4021 | } | |
4022 | } | |
4023 | ||
4024 | void | |
4025 | const_folder::visit_for_loop (for_loop* s) | |
4026 | { | |
4027 | literal_number* cond = get_number (s->cond); | |
4028 | if (!cond || cond->value) | |
4029 | { | |
4030 | replace (s->init); | |
4031 | replace (s->incr); | |
4032 | replace (s->block); | |
4033 | provide (s); | |
4034 | } | |
4035 | else | |
4036 | { | |
4037 | if (session.verbose>2) | |
4af765b2 | 4038 | clog << _("Collapsing constantly-false for-loop ") << *s->tok << endl; |
10328bcf JS |
4039 | relaxed_p = false; |
4040 | ||
4041 | if (s->init) | |
4042 | s->init->visit (this); | |
4043 | else | |
4044 | provide (new null_statement (s->tok)); | |
4045 | } | |
4046 | } | |
4047 | ||
4048 | void | |
4049 | const_folder::visit_foreach_loop (foreach_loop* s) | |
4050 | { | |
4051 | literal_number* limit = get_number (s->limit); | |
4052 | if (!limit || limit->value > 0) | |
4053 | { | |
4054 | for (unsigned i = 0; i < s->indexes.size(); ++i) | |
4055 | replace (s->indexes[i]); | |
4056 | replace (s->base); | |
c261711d | 4057 | replace (s->value); |
10328bcf JS |
4058 | replace (s->block); |
4059 | provide (s); | |
4060 | } | |
4061 | else | |
4062 | { | |
4063 | if (session.verbose>2) | |
4af765b2 | 4064 | clog << _("Collapsing constantly-limited foreach-loop ") << *s->tok << endl; |
10328bcf JS |
4065 | relaxed_p = false; |
4066 | ||
4067 | provide (new null_statement (s->tok)); | |
4068 | } | |
4069 | } | |
4070 | ||
4071 | void | |
4072 | const_folder::visit_binary_expression (binary_expression* e) | |
4073 | { | |
e7227e90 JS |
4074 | int64_t value; |
4075 | literal_number* left = get_number (e->left); | |
4076 | literal_number* right = get_number (e->right); | |
4077 | ||
4078 | if (right && !right->value && (e->op == "/" || e->op == "%")) | |
4079 | { | |
4080 | // Give divide-by-zero a chance to be optimized out elsewhere, | |
4081 | // and if not it will be a runtime error anyway... | |
4082 | provide (e); | |
4083 | return; | |
4084 | } | |
4085 | ||
4086 | if (left && right) | |
4087 | { | |
4088 | if (e->op == "+") | |
4089 | value = left->value + right->value; | |
4090 | else if (e->op == "-") | |
4091 | value = left->value - right->value; | |
4092 | else if (e->op == "*") | |
4093 | value = left->value * right->value; | |
4094 | else if (e->op == "&") | |
4095 | value = left->value & right->value; | |
4096 | else if (e->op == "|") | |
4097 | value = left->value | right->value; | |
4098 | else if (e->op == "^") | |
4099 | value = left->value ^ right->value; | |
4100 | else if (e->op == ">>") | |
4101 | value = left->value >> max(min(right->value, (int64_t)64), (int64_t)0); | |
4102 | else if (e->op == "<<") | |
4103 | value = left->value << max(min(right->value, (int64_t)64), (int64_t)0); | |
4104 | else if (e->op == "/") | |
4105 | value = (left->value == LLONG_MIN && right->value == -1) ? LLONG_MIN : | |
4106 | left->value / right->value; | |
4107 | else if (e->op == "%") | |
4108 | value = (left->value == LLONG_MIN && right->value == -1) ? 0 : | |
4109 | left->value % right->value; | |
4110 | else | |
47d349b1 | 4111 | throw SEMANTIC_ERROR (_("unsupported binary operator ") + (string)e->op); |
e7227e90 JS |
4112 | } |
4113 | ||
4114 | else if ((left && ((left->value == 0 && (e->op == "*" || e->op == "&" || | |
4115 | e->op == ">>" || e->op == "<<" )) || | |
4116 | (left->value ==-1 && (e->op == "|" || e->op == ">>")))) | |
4117 | || | |
4118 | (right && ((right->value == 0 && (e->op == "*" || e->op == "&")) || | |
4119 | (right->value == 1 && (e->op == "%")) || | |
4120 | (right->value ==-1 && (e->op == "%" || e->op == "|"))))) | |
4121 | { | |
4122 | expression* other = left ? e->right : e->left; | |
4123 | varuse_collecting_visitor vu(session); | |
4124 | other->visit(&vu); | |
4125 | if (!vu.side_effect_free()) | |
4126 | { | |
4127 | provide (e); | |
4128 | return; | |
4129 | } | |
4130 | ||
cde4a9fe AJ |
4131 | // we'll pass on type=pe_long inference to the expression |
4132 | if (other->type == pe_unknown) | |
4133 | other->type = pe_long; | |
61f79792 AJ |
4134 | else if (other->type != pe_long) |
4135 | { | |
4136 | // this mismatch was not caught in the initial type resolution pass, | |
4137 | // generate a mismatch (left doesn't match right) error | |
4138 | typeresolution_info ti(session); | |
4139 | ti.assert_resolvability = true; // need this to get it throw errors | |
4140 | ti.mismatch_complexity = 1; // also needed to throw errors | |
4141 | ti.mismatch(e); | |
4142 | } | |
1860faba | 4143 | |
e7227e90 JS |
4144 | if (left) |
4145 | value = left->value; | |
4146 | else if (e->op == "%") | |
4147 | value = 0; | |
4148 | else | |
4149 | value = right->value; | |
4150 | } | |
4151 | ||
4152 | else if ((left && ((left->value == 0 && (e->op == "+" || e->op == "|" || | |
4153 | e->op == "^")) || | |
4154 | (left->value == 1 && (e->op == "*")) || | |
4155 | (left->value ==-1 && (e->op == "&")))) | |
4156 | || | |
4157 | (right && ((right->value == 0 && (e->op == "+" || e->op == "-" || | |
4158 | e->op == "|" || e->op == "^")) || | |
4159 | (right->value == 1 && (e->op == "*" || e->op == "/")) || | |
4160 | (right->value ==-1 && (e->op == "&")) || | |
4161 | (right->value <= 0 && (e->op == ">>" || e->op == "<<"))))) | |
4162 | { | |
4163 | if (session.verbose>2) | |
4af765b2 | 4164 | clog << _("Collapsing constant-identity binary operator ") << *e->tok << endl; |
e7227e90 JS |
4165 | relaxed_p = false; |
4166 | ||
cde4a9fe | 4167 | // we'll pass on type=pe_long inference to the expression |
1860faba AJ |
4168 | expression* other = left ? e->right : e->left; |
4169 | if (other->type == pe_unknown) | |
4170 | other->type = pe_long; | |
61f79792 AJ |
4171 | else if (other->type != pe_long) |
4172 | { | |
4173 | // this mismatch was not caught in the initial type resolution pass, | |
4174 | // generate a mismatch (left doesn't match right) error | |
4175 | typeresolution_info ti(session); | |
4176 | ti.assert_resolvability = true; // need this to get it throw errors | |
4177 | ti.mismatch_complexity = 1; // also needed to throw errors | |
4178 | ti.mismatch(e); | |
4179 | } | |
1860faba AJ |
4180 | |
4181 | provide (other); | |
e7227e90 JS |
4182 | return; |
4183 | } | |
4184 | ||
4185 | else | |
4186 | { | |
4187 | provide (e); | |
4188 | return; | |
4189 | } | |
4190 | ||
4191 | if (session.verbose>2) | |
4af765b2 LB |
4192 | clog << _F("Collapsing constant-%" PRIi64 " binary operator %s", |
4193 | value, lex_cast(*e->tok).c_str()) << endl; | |
e7227e90 JS |
4194 | relaxed_p = false; |
4195 | ||
4196 | literal_number* n = new literal_number(value); | |
4197 | n->tok = e->tok; | |
4198 | n->visit (this); | |
10328bcf JS |
4199 | } |
4200 | ||
4201 | void | |
4202 | const_folder::visit_unary_expression (unary_expression* e) | |
4203 | { | |
4204 | literal_number* operand = get_number (e->operand); | |
4205 | if (!operand) | |
4206 | provide (e); | |
4207 | else | |
4208 | { | |
4209 | if (session.verbose>2) | |
4af765b2 | 4210 | clog << _("Collapsing constant unary ") << *e->tok << endl; |
10328bcf JS |
4211 | relaxed_p = false; |
4212 | ||
4213 | literal_number* n = new literal_number (*operand); | |
4214 | n->tok = e->tok; | |
4215 | if (e->op == "+") | |
4216 | ; // nothing to do | |
4217 | else if (e->op == "-") | |
4218 | n->value = -n->value; | |
4219 | else if (e->op == "!") | |
4220 | n->value = !n->value; | |
4221 | else if (e->op == "~") | |
4222 | n->value = ~n->value; | |
4223 | else | |
47d349b1 | 4224 | throw SEMANTIC_ERROR (_("unsupported unary operator ") + (string)e->op); |
10328bcf JS |
4225 | n->visit (this); |
4226 | } | |
4227 | } | |
4228 | ||
4229 | void | |
4230 | const_folder::visit_logical_or_expr (logical_or_expr* e) | |
4231 | { | |
a7e58d4c JS |
4232 | int64_t value; |
4233 | literal_number* left = get_number (e->left); | |
4234 | literal_number* right = get_number (e->right); | |
4235 | ||
4236 | if (left && right) | |
4237 | value = left->value || right->value; | |
4238 | ||
4239 | else if ((left && left->value) || (right && right->value)) | |
4240 | { | |
4241 | // If the const is on the left, we get to short-circuit the right | |
4242 | // immediately. Otherwise, we can only eliminate the LHS if it's pure. | |
4243 | if (right) | |
4244 | { | |
4245 | varuse_collecting_visitor vu(session); | |
4246 | e->left->visit(&vu); | |
4247 | if (!vu.side_effect_free()) | |
4248 | { | |
4249 | provide (e); | |
4250 | return; | |
4251 | } | |
4252 | } | |
4253 | ||
4254 | value = 1; | |
4255 | } | |
4256 | ||
4257 | // We might also get rid of useless "0||x" and "x||0", except it does | |
4258 | // normalize x to 0 or 1. We could change it to "!!x", but it's not clear | |
4259 | // that this would gain us much. | |
4260 | ||
4261 | else | |
4262 | { | |
4263 | provide (e); | |
4264 | return; | |
4265 | } | |
4266 | ||
4267 | if (session.verbose>2) | |
4af765b2 | 4268 | clog << _("Collapsing constant logical-OR ") << *e->tok << endl; |
a7e58d4c JS |
4269 | relaxed_p = false; |
4270 | ||
4271 | literal_number* n = new literal_number(value); | |
4272 | n->tok = e->tok; | |
4273 | n->visit (this); | |
10328bcf JS |
4274 | } |
4275 | ||
4276 | void | |
4277 | const_folder::visit_logical_and_expr (logical_and_expr* e) | |
4278 | { | |
a7e58d4c JS |
4279 | int64_t value; |
4280 | literal_number* left = get_number (e->left); | |
4281 | literal_number* right = get_number (e->right); | |
4282 | ||
4283 | if (left && right) | |
4284 | value = left->value && right->value; | |
4285 | ||
4286 | else if ((left && !left->value) || (right && !right->value)) | |
4287 | { | |
4288 | // If the const is on the left, we get to short-circuit the right | |
4289 | // immediately. Otherwise, we can only eliminate the LHS if it's pure. | |
4290 | if (right) | |
4291 | { | |
4292 | varuse_collecting_visitor vu(session); | |
4293 | e->left->visit(&vu); | |
4294 | if (!vu.side_effect_free()) | |
4295 | { | |
4296 | provide (e); | |
4297 | return; | |
4298 | } | |
4299 | } | |
4300 | ||
4301 | value = 0; | |
4302 | } | |
4303 | ||
4304 | // We might also get rid of useless "1&&x" and "x&&1", except it does | |
4305 | // normalize x to 0 or 1. We could change it to "!!x", but it's not clear | |
4306 | // that this would gain us much. | |
4307 | ||
4308 | else | |
4309 | { | |
4310 | provide (e); | |
4311 | return; | |
4312 | } | |
4313 | ||
4314 | if (session.verbose>2) | |
4af765b2 | 4315 | clog << _("Collapsing constant logical-AND ") << *e->tok << endl; |
a7e58d4c JS |
4316 | relaxed_p = false; |
4317 | ||
4318 | literal_number* n = new literal_number(value); | |
4319 | n->tok = e->tok; | |
4320 | n->visit (this); | |
10328bcf JS |
4321 | } |
4322 | ||
4323 | void | |
4324 | const_folder::visit_comparison (comparison* e) | |
4325 | { | |
f4869658 JS |
4326 | int comp; |
4327 | ||
4328 | literal_number *left_num, *right_num; | |
4329 | literal_string *left_str, *right_str; | |
4330 | get_literal(e->left, left_num, left_str); | |
4331 | get_literal(e->right, right_num, right_str); | |
4332 | ||
4333 | if (left_str && right_str) | |
4334 | comp = left_str->value.compare(right_str->value); | |
4335 | ||
4336 | else if (left_num && right_num) | |
4337 | comp = left_num->value < right_num->value ? -1 : | |
4338 | left_num->value > right_num->value ? 1 : 0; | |
4339 | ||
4340 | else if ((left_num && ((left_num->value == LLONG_MIN && | |
4341 | (e->op == "<=" || e->op == ">")) || | |
4342 | (left_num->value == LLONG_MAX && | |
4343 | (e->op == ">=" || e->op == "<")))) | |
4344 | || | |
4345 | (right_num && ((right_num->value == LLONG_MIN && | |
4346 | (e->op == ">=" || e->op == "<")) || | |
4347 | (right_num->value == LLONG_MAX && | |
4348 | (e->op == "<=" || e->op == ">"))))) | |
4349 | { | |
4350 | expression* other = left_num ? e->right : e->left; | |
4351 | varuse_collecting_visitor vu(session); | |
4352 | other->visit(&vu); | |
4353 | if (!vu.side_effect_free()) | |
4354 | provide (e); | |
4355 | else | |
4356 | { | |
4357 | if (session.verbose>2) | |
4af765b2 | 4358 | clog << _("Collapsing constant-boundary comparison ") << *e->tok << endl; |
f4869658 JS |
4359 | relaxed_p = false; |
4360 | ||
4361 | // ops <= and >= are true, < and > are false | |
4362 | literal_number* n = new literal_number( e->op.length() == 2 ); | |
4363 | n->tok = e->tok; | |
4364 | n->visit (this); | |
4365 | } | |
4366 | return; | |
4367 | } | |
4368 | ||
4369 | else | |
4370 | { | |
4371 | provide (e); | |
4372 | return; | |
4373 | } | |
4374 | ||
4375 | if (session.verbose>2) | |
4af765b2 | 4376 | clog << _("Collapsing constant comparison ") << *e->tok << endl; |
f4869658 JS |
4377 | relaxed_p = false; |
4378 | ||
4379 | int64_t value; | |
4380 | if (e->op == "==") | |
4381 | value = comp == 0; | |
4382 | else if (e->op == "!=") | |
4383 | value = comp != 0; | |
4384 | else if (e->op == "<") | |
4385 | value = comp < 0; | |
4386 | else if (e->op == ">") | |
4387 | value = comp > 0; | |
4388 | else if (e->op == "<=") | |
4389 | value = comp <= 0; | |
4390 | else if (e->op == ">=") | |
4391 | value = comp >= 0; | |
4392 | else | |
47d349b1 | 4393 | throw SEMANTIC_ERROR (_("unsupported comparison operator ") + (string)e->op); |
f4869658 JS |
4394 | |
4395 | literal_number* n = new literal_number(value); | |
4396 | n->tok = e->tok; | |
4397 | n->visit (this); | |
10328bcf JS |
4398 | } |
4399 | ||
4400 | void | |
4401 | const_folder::visit_concatenation (concatenation* e) | |
4402 | { | |
29b1a9b7 JS |
4403 | literal_string* left = get_string (e->left); |
4404 | literal_string* right = get_string (e->right); | |
4405 | ||
4406 | if (left && right) | |
4407 | { | |
4408 | if (session.verbose>2) | |
4af765b2 | 4409 | clog << _("Collapsing constant concatenation ") << *e->tok << endl; |
29b1a9b7 JS |
4410 | relaxed_p = false; |
4411 | ||
4412 | literal_string* n = new literal_string (*left); | |
4413 | n->tok = e->tok; | |
47d349b1 | 4414 | n->value = (string)n->value + (string)right->value; |
29b1a9b7 JS |
4415 | n->visit (this); |
4416 | } | |
4417 | else if ((left && left->value.empty()) || | |
4418 | (right && right->value.empty())) | |
4419 | { | |
4420 | if (session.verbose>2) | |
4af765b2 | 4421 | clog << _("Collapsing identity concatenation ") << *e->tok << endl; |
29b1a9b7 JS |
4422 | relaxed_p = false; |
4423 | provide(left ? e->right : e->left); | |
4424 | } | |
4425 | else | |
4426 | provide (e); | |
10328bcf JS |
4427 | } |
4428 | ||
4429 | void | |
4430 | const_folder::visit_ternary_expression (ternary_expression* e) | |
4431 | { | |
4432 | literal_number* cond = get_number (e->cond); | |
4433 | if (!cond) | |
4434 | { | |
4435 | replace (e->truevalue); | |
4436 | replace (e->falsevalue); | |
4437 | provide (e); | |
4438 | } | |
4439 | else | |
4440 | { | |
4441 | if (session.verbose>2) | |
4af765b2 LB |
4442 | clog << _F("Collapsing constant-%" PRIi64 " ternary %s", |
4443 | cond->value, lex_cast(*e->tok).c_str()) << endl; | |
10328bcf JS |
4444 | relaxed_p = false; |
4445 | ||
4446 | expression* n = cond->value ? e->truevalue : e->falsevalue; | |
4447 | n->visit (this); | |
4448 | } | |
4449 | } | |
4450 | ||
b7aedf26 JS |
4451 | void |
4452 | const_folder::visit_defined_op (defined_op* e) | |
4453 | { | |
4454 | // If a @defined makes it this far, then it is, de facto, undefined. | |
4455 | ||
4456 | if (session.verbose>2) | |
4af765b2 | 4457 | clog << _("Collapsing untouched @defined check ") << *e->tok << endl; |
b7aedf26 JS |
4458 | relaxed_p = false; |
4459 | ||
4460 | literal_number* n = new literal_number (0); | |
4461 | n->tok = e->tok; | |
4462 | n->visit (this); | |
4463 | } | |
4464 | ||
9fab2262 JS |
4465 | void |
4466 | const_folder::visit_target_symbol (target_symbol* e) | |
4467 | { | |
a45664f4 | 4468 | if (session.skip_badvars) |
9fab2262 JS |
4469 | { |
4470 | // Upon user request for ignoring context, the symbol is replaced | |
4471 | // with a literal 0 and a warning message displayed | |
4472 | // XXX this ignores possible side-effects, e.g. in array indexes | |
4473 | literal_number* ln_zero = new literal_number (0); | |
4474 | ln_zero->tok = e->tok; | |
4475 | provide (ln_zero); | |
bad814e8 | 4476 | session.print_warning (_("Bad $context variable being substituted with literal 0"), |
9fab2262 | 4477 | e->tok); |
9fab2262 JS |
4478 | relaxed_p = false; |
4479 | } | |
4480 | else | |
4481 | update_visitor::visit_target_symbol (e); | |
4482 | } | |
4483 | ||
4375d018 AJ |
4484 | static int initial_typeres_pass(systemtap_session& s); |
4485 | static int semantic_pass_const_fold (systemtap_session& s, bool& relaxed_p) | |
10328bcf | 4486 | { |
cde4a9fe AJ |
4487 | // attempt an initial type resolution pass to see if there are any type |
4488 | // mismatches before we starting whisking away vars that get switched out | |
4489 | // with a const. | |
4375d018 AJ |
4490 | |
4491 | // return if the initial type resolution pass reported errors (type mismatches) | |
4492 | int rc = initial_typeres_pass(s); | |
4493 | if (rc) | |
4494 | { | |
4495 | relaxed_p = true; | |
4496 | return rc; | |
4497 | } | |
10328bcf | 4498 | |
cde4a9fe | 4499 | // Let's simplify statements with constant values. |
10328bcf JS |
4500 | const_folder cf (s, relaxed_p); |
4501 | // This instance may be reused for multiple probe/function body trims. | |
4502 | ||
4503 | for (unsigned i=0; i<s.probes.size(); i++) | |
4504 | cf.replace (s.probes[i]->body); | |
4505 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); | |
4506 | it != s.functions.end(); it++) | |
4507 | cf.replace (it->second->body); | |
4375d018 | 4508 | return 0; |
10328bcf JS |
4509 | } |
4510 | ||
4511 | ||
7c3feb93 JS |
4512 | struct dead_control_remover: public traversing_visitor |
4513 | { | |
4514 | systemtap_session& session; | |
4515 | bool& relaxed_p; | |
4516 | statement* control; | |
4517 | ||
4518 | dead_control_remover(systemtap_session& s, bool& r): | |
4519 | session(s), relaxed_p(r), control(NULL) {} | |
4520 | ||
4521 | void visit_block (block *b); | |
4522 | ||
4523 | // When a block contains any of these, the following statements are dead. | |
4524 | void visit_return_statement (return_statement* s) { control = s; } | |
4525 | void visit_next_statement (next_statement* s) { control = s; } | |
4526 | void visit_break_statement (break_statement* s) { control = s; } | |
4527 | void visit_continue_statement (continue_statement* s) { control = s; } | |
4528 | }; | |
4529 | ||
4530 | ||
4531 | void dead_control_remover::visit_block (block* b) | |
4532 | { | |
4533 | vector<statement*>& vs = b->statements; | |
a1a230af FCE |
4534 | if (vs.size() == 0) /* else (size_t) size()-1 => very big */ |
4535 | return; | |
7c3feb93 JS |
4536 | for (size_t i = 0; i < vs.size() - 1; ++i) |
4537 | { | |
4538 | vs[i]->visit (this); | |
4539 | if (vs[i] == control) | |
4540 | { | |
4541 | session.print_warning(_("statement will never be reached"), | |
4542 | vs[i + 1]->tok); | |
4543 | vs.erase(vs.begin() + i + 1, vs.end()); | |
4544 | relaxed_p = false; | |
4545 | break; | |
4546 | } | |
4547 | } | |
4548 | } | |
4549 | ||
4550 | ||
4551 | static void semantic_pass_dead_control (systemtap_session& s, bool& relaxed_p) | |
4552 | { | |
4553 | // Let's remove code that follow unconditional control statements | |
4554 | ||
4555 | dead_control_remover dc (s, relaxed_p); | |
4556 | ||
4557 | for (unsigned i=0; i<s.probes.size(); i++) | |
4558 | s.probes[i]->body->visit(&dc); | |
4559 | ||
4560 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); | |
4561 | it != s.functions.end(); it++) | |
4562 | it->second->body->visit(&dc); | |
4563 | } | |
4564 | ||
4565 | ||
88bbd60d DS |
4566 | struct duplicate_function_remover: public functioncall_traversing_visitor |
4567 | { | |
4568 | systemtap_session& s; | |
88bbd60d DS |
4569 | map<functiondecl*, functiondecl*>& duplicate_function_map; |
4570 | ||
c214bd6a | 4571 | duplicate_function_remover(systemtap_session& sess, |
88bbd60d | 4572 | map<functiondecl*, functiondecl*>&dfm): |
c214bd6a | 4573 | s(sess), duplicate_function_map(dfm) {}; |
88bbd60d DS |
4574 | |
4575 | void visit_functioncall (functioncall* e); | |
4576 | }; | |
4577 | ||
4578 | void | |
4579 | duplicate_function_remover::visit_functioncall (functioncall *e) | |
4580 | { | |
4581 | functioncall_traversing_visitor::visit_functioncall (e); | |
4582 | ||
7b5b30a8 | 4583 | // If any of the current function call references points to a function that |
88bbd60d | 4584 | // is a duplicate, replace it. |
7b5b30a8 | 4585 | for (unsigned i = 0; i < e->referents.size(); i++) |
88bbd60d | 4586 | { |
7b5b30a8 FL |
4587 | functiondecl* referent = e->referents[i]; |
4588 | if (duplicate_function_map.count(referent) != 0) | |
4589 | { | |
4590 | if (s.verbose>2) | |
4591 | clog << _F("Changing %s reference to %s reference\n", | |
4592 | referent->unmangled_name.to_string().c_str(), | |
4593 | duplicate_function_map[referent]->unmangled_name.to_string().c_str()); | |
4594 | e->tok = duplicate_function_map[referent]->tok; | |
4595 | e->function = duplicate_function_map[referent]->name; | |
4596 | e->referents[i] = duplicate_function_map[referent]; | |
4597 | } | |
88bbd60d DS |
4598 | } |
4599 | } | |
4600 | ||
4601 | static string | |
4602 | get_functionsig (functiondecl* f) | |
4603 | { | |
4604 | ostringstream s; | |
4605 | ||
4606 | // Get the "name:args body" of the function in s. We have to | |
4607 | // include the args since the function 'x1(a, b)' is different than | |
4608 | // the function 'x2(b, a)' even if the bodies of the two functions | |
4609 | // are exactly the same. | |
4610 | f->printsig(s); | |
4611 | f->body->print(s); | |
4612 | ||
4613 | // printsig puts f->name + ':' on the front. Remove this | |
4614 | // (otherwise, functions would never compare equal). | |
7b5b30a8 | 4615 | string str = s.str().erase(0, f->unmangled_name.size() + 1); |
88bbd60d DS |
4616 | |
4617 | // Return the function signature. | |
4618 | return str; | |
4619 | } | |
4620 | ||
bea72737 | 4621 | void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p) |
88bbd60d DS |
4622 | { |
4623 | // Walk through all the functions, looking for duplicates. | |
4624 | map<string, functiondecl*> functionsig_map; | |
4625 | map<functiondecl*, functiondecl*> duplicate_function_map; | |
f76427a2 FCE |
4626 | |
4627 | ||
4628 | vector<functiondecl*> newly_zapped_functions; | |
4629 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) | |
88bbd60d | 4630 | { |
f76427a2 FCE |
4631 | functiondecl *fd = it->second; |
4632 | string functionsig = get_functionsig(fd); | |
88bbd60d DS |
4633 | |
4634 | if (functionsig_map.count(functionsig) == 0) | |
c214bd6a DS |
4635 | { |
4636 | // This function is unique. Remember it. | |
f76427a2 | 4637 | functionsig_map[functionsig] = fd; |
c214bd6a | 4638 | } |
88bbd60d | 4639 | else |
c214bd6a DS |
4640 | { |
4641 | // This function is a duplicate. | |
f76427a2 FCE |
4642 | duplicate_function_map[fd] = functionsig_map[functionsig]; |
4643 | newly_zapped_functions.push_back (fd); | |
c214bd6a | 4644 | relaxed_p = false; |
c214bd6a | 4645 | } |
88bbd60d | 4646 | } |
f76427a2 FCE |
4647 | for (unsigned i=0; i<newly_zapped_functions.size(); i++) |
4648 | { | |
4649 | map<string,functiondecl*>::iterator where = s.functions.find (newly_zapped_functions[i]->name); | |
4650 | assert (where != s.functions.end()); | |
4651 | s.functions.erase (where); | |
4652 | } | |
4653 | ||
88bbd60d DS |
4654 | |
4655 | // If we have duplicate functions, traverse down the tree, replacing | |
4656 | // the appropriate function calls. | |
4657 | // duplicate_function_remover::visit_functioncall() handles the | |
c214bd6a | 4658 | // details of replacing the function calls. |
88bbd60d DS |
4659 | if (duplicate_function_map.size() != 0) |
4660 | { | |
c214bd6a | 4661 | duplicate_function_remover dfr (s, duplicate_function_map); |
88bbd60d DS |
4662 | |
4663 | for (unsigned i=0; i < s.probes.size(); i++) | |
4664 | s.probes[i]->body->visit(&dfr); | |
4665 | } | |
4666 | } | |
4667 | ||
cdda9521 | 4668 | struct stable_analysis: public embedded_tags_visitor |
0e658756 FL |
4669 | { |
4670 | bool stable; | |
1aad7ed4 | 4671 | stable_analysis(): embedded_tags_visitor(true), stable(false) {}; |
cdda9521 | 4672 | |
1aad7ed4 | 4673 | void visit_embeddedcode (embeddedcode* s); |
cdda9521 | 4674 | void visit_functioncall (functioncall* e); |
0e658756 FL |
4675 | }; |
4676 | ||
1aad7ed4 | 4677 | void stable_analysis::visit_embeddedcode (embeddedcode* s) |
0e658756 | 4678 | { |
1aad7ed4 | 4679 | embedded_tags_visitor::visit_embeddedcode(s); |
0e658756 FL |
4680 | if (tagged_p("/* stable */")) |
4681 | stable = true; | |
1aad7ed4 FL |
4682 | if (stable && !tagged_p("/* pure */")) |
4683 | throw SEMANTIC_ERROR(_("stable function must also be /* pure */"), | |
4684 | s->tok); | |
0e658756 FL |
4685 | } |
4686 | ||
dabd71bb | 4687 | void stable_analysis::visit_functioncall (functioncall*) |
cdda9521 | 4688 | { |
1aad7ed4 | 4689 | } |
cdda9521 | 4690 | |
1aad7ed4 FL |
4691 | // Examines entire subtree for any stable functioncalls. |
4692 | struct stable_finder: public traversing_visitor | |
4693 | { | |
4694 | bool stable; | |
4695 | set<string>& stable_fcs; | |
4696 | stable_finder(set<string>&s): stable(false), stable_fcs(s) {}; | |
4697 | void visit_functioncall (functioncall* e); | |
4698 | }; | |
cdda9521 | 4699 | |
1aad7ed4 FL |
4700 | void stable_finder::visit_functioncall (functioncall* e) |
4701 | { | |
4702 | if (stable_fcs.find(e->function) != stable_fcs.end()) | |
4703 | stable = true; | |
2a4b3a65 | 4704 | traversing_visitor::visit_functioncall(e); |
cdda9521 FL |
4705 | } |
4706 | ||
4707 | // Examines current level of block for stable functioncalls. | |
4708 | // Does not descend into sublevels. | |
4709 | struct level_check: public traversing_visitor | |
4710 | { | |
1aad7ed4 | 4711 | bool stable; |
cdda9521 | 4712 | set<string>& stable_fcs; |
1aad7ed4 FL |
4713 | level_check(set<string>& s): stable(false), stable_fcs(s) {}; |
4714 | ||
cdda9521 FL |
4715 | void visit_block (block* s); |
4716 | void visit_try_block (try_block *s); | |
4717 | void visit_if_statement (if_statement* s); | |
4718 | void visit_for_loop (for_loop* s); | |
4719 | void visit_foreach_loop (foreach_loop* s); | |
4720 | void visit_functioncall (functioncall* s); | |
4721 | }; | |
4722 | ||
dabd71bb | 4723 | void level_check::visit_block (block*) |
cdda9521 FL |
4724 | { |
4725 | } | |
4726 | ||
4727 | void level_check::visit_try_block (try_block* s) | |
4728 | { | |
1aad7ed4 FL |
4729 | if (s->catch_error_var) |
4730 | s->catch_error_var->visit(this); | |
cdda9521 FL |
4731 | } |
4732 | ||
4733 | void level_check::visit_if_statement (if_statement* s) | |
4734 | { | |
1aad7ed4 | 4735 | s->condition->visit(this); |
cdda9521 FL |
4736 | } |
4737 | ||
4738 | void level_check::visit_for_loop (for_loop* s) | |
4739 | { | |
1aad7ed4 FL |
4740 | if (s->init) s->init->visit(this); |
4741 | s->cond->visit(this); | |
4742 | if (s->incr) s->incr->visit(this); | |
cdda9521 FL |
4743 | } |
4744 | ||
4745 | void level_check::visit_foreach_loop (foreach_loop* s) | |
4746 | { | |
1aad7ed4 FL |
4747 | s->base->visit(this); |
4748 | ||
cdda9521 | 4749 | for (unsigned i=0; i<s->indexes.size(); i++) |
1aad7ed4 | 4750 | s->indexes[i]->visit(this); |
cdda9521 FL |
4751 | |
4752 | if (s->value) | |
1aad7ed4 | 4753 | s->value->visit(this); |
cdda9521 FL |
4754 | |
4755 | if (s->limit) | |
1aad7ed4 | 4756 | s->limit->visit(this); |
cdda9521 FL |
4757 | } |
4758 | ||
4759 | void level_check::visit_functioncall (functioncall* e) | |
4760 | { | |
4761 | if (stable_fcs.find(e->function) != stable_fcs.end()) | |
1aad7ed4 | 4762 | stable = true; |
2a4b3a65 | 4763 | traversing_visitor::visit_functioncall(e); |
cdda9521 FL |
4764 | } |
4765 | ||
4766 | struct stable_functioncall_visitor: public update_visitor | |
0e658756 FL |
4767 | { |
4768 | systemtap_session& session; | |
4769 | functiondecl* current_function; | |
4770 | derived_probe* current_probe; | |
cdda9521 FL |
4771 | set<string>& stable_fcs; |
4772 | set<string> scope_vars; | |
4773 | map<string,vardecl*> new_vars; | |
4774 | vector<pair<expr_statement*,block*> > new_stmts; | |
5e41c8bc FL |
4775 | unsigned loop_depth; |
4776 | block* top_scope; | |
1aad7ed4 | 4777 | block* curr_scope; |
cdda9521 | 4778 | stable_functioncall_visitor(systemtap_session& s, set<string>& sfc): |
5e41c8bc | 4779 | session(s), current_function(0), current_probe(0), stable_fcs(sfc), |
45a1aa33 | 4780 | loop_depth(0), top_scope(0), curr_scope(0) {}; |
cdda9521 FL |
4781 | |
4782 | statement* convert_stmt(statement* s); | |
4783 | void visit_block (block* s); | |
4784 | void visit_try_block (try_block* s); | |
4785 | void visit_if_statement (if_statement* s); | |
4786 | void visit_for_loop (for_loop* s); | |
4787 | void visit_foreach_loop (foreach_loop* s); | |
0e658756 FL |
4788 | void visit_functioncall (functioncall* e); |
4789 | }; | |
4790 | ||
cdda9521 | 4791 | statement* stable_functioncall_visitor::convert_stmt (statement* s) |
0e658756 | 4792 | { |
1aad7ed4 FL |
4793 | if (top_scope == 0 && |
4794 | (dynamic_cast<for_loop*>(s) || dynamic_cast<foreach_loop*>(s))) | |
5e41c8bc | 4795 | { |
1aad7ed4 FL |
4796 | stable_finder sf(stable_fcs); |
4797 | s->visit(&sf); | |
4798 | if (sf.stable) | |
5e41c8bc FL |
4799 | { |
4800 | block* b = new block; | |
4801 | b->tok = s->tok; | |
4802 | b->statements.push_back(s); | |
5e41c8bc FL |
4803 | return b; |
4804 | } | |
4805 | } | |
1aad7ed4 | 4806 | else if (top_scope == 0 && !dynamic_cast<block*>(s)) |
0e658756 | 4807 | { |
1aad7ed4 FL |
4808 | level_check lc(stable_fcs); |
4809 | s->visit(&lc); | |
4810 | if (lc.stable) | |
4811 | { | |
4812 | block* b = new block; | |
4813 | b->tok = s->tok; | |
4814 | b->statements.push_back(s); | |
4815 | return b; | |
4816 | } | |
cdda9521 FL |
4817 | } |
4818 | ||
4819 | return s; | |
4820 | } | |
0e658756 | 4821 | |
cdda9521 FL |
4822 | void stable_functioncall_visitor::visit_block (block* s) |
4823 | { | |
1aad7ed4 FL |
4824 | block* prev_top_scope = top_scope; |
4825 | block* prev_scope = curr_scope; | |
5e41c8bc FL |
4826 | if (loop_depth == 0) |
4827 | top_scope = s; | |
1aad7ed4 | 4828 | curr_scope = s; |
cdda9521 | 4829 | set<string> current_vars = scope_vars; |
5e41c8bc | 4830 | |
cdda9521 | 4831 | update_visitor::visit_block(s); |
5e41c8bc FL |
4832 | |
4833 | if (loop_depth == 0) | |
1aad7ed4 FL |
4834 | top_scope = prev_top_scope; |
4835 | curr_scope = prev_scope; | |
5e41c8bc | 4836 | scope_vars = current_vars; |
cdda9521 | 4837 | } |
0e658756 | 4838 | |
cdda9521 FL |
4839 | void stable_functioncall_visitor::visit_try_block (try_block* s) |
4840 | { | |
4841 | if (s->try_block) | |
4842 | s->try_block = convert_stmt(s->try_block); | |
1aad7ed4 FL |
4843 | replace(s->try_block); |
4844 | replace(s->catch_error_var); | |
cdda9521 FL |
4845 | if (s->catch_block) |
4846 | s->catch_block = convert_stmt(s->catch_block); | |
1aad7ed4 FL |
4847 | replace(s->catch_block); |
4848 | provide(s); | |
cdda9521 | 4849 | } |
0e658756 | 4850 | |
cdda9521 FL |
4851 | void stable_functioncall_visitor::visit_if_statement (if_statement* s) |
4852 | { | |
1aad7ed4 FL |
4853 | block* prev_top_scope = top_scope; |
4854 | ||
5e41c8bc FL |
4855 | if (loop_depth == 0) |
4856 | top_scope = 0; | |
1aad7ed4 | 4857 | replace(s->condition); |
cdda9521 | 4858 | s->thenblock = convert_stmt(s->thenblock); |
1aad7ed4 FL |
4859 | replace(s->thenblock); |
4860 | if (loop_depth == 0) | |
4861 | top_scope = 0; | |
cdda9521 FL |
4862 | if (s->elseblock) |
4863 | s->elseblock = convert_stmt(s->elseblock); | |
1aad7ed4 FL |
4864 | replace(s->elseblock); |
4865 | provide(s); | |
4866 | ||
4867 | top_scope = prev_top_scope; | |
cdda9521 FL |
4868 | } |
4869 | ||
4870 | void stable_functioncall_visitor::visit_for_loop (for_loop* s) | |
4871 | { | |
1aad7ed4 FL |
4872 | replace(s->init); |
4873 | replace(s->cond); | |
4874 | replace(s->incr); | |
5e41c8bc | 4875 | loop_depth++; |
cdda9521 | 4876 | s->block = convert_stmt(s->block); |
1aad7ed4 | 4877 | replace(s->block); |
5e41c8bc | 4878 | loop_depth--; |
1aad7ed4 | 4879 | provide(s); |
cdda9521 FL |
4880 | } |
4881 | ||
4882 | void stable_functioncall_visitor::visit_foreach_loop (foreach_loop* s) | |
4883 | { | |
1aad7ed4 FL |
4884 | for (unsigned i = 0; i < s->indexes.size(); ++i) |
4885 | replace(s->indexes[i]); | |
4886 | replace(s->base); | |
4887 | replace(s->value); | |
4888 | replace(s->limit); | |
5e41c8bc | 4889 | loop_depth++; |
cdda9521 | 4890 | s->block = convert_stmt(s->block); |
1aad7ed4 | 4891 | replace(s->block); |
5e41c8bc | 4892 | loop_depth--; |
1aad7ed4 | 4893 | provide(s); |
cdda9521 FL |
4894 | } |
4895 | ||
4896 | void stable_functioncall_visitor::visit_functioncall (functioncall* e) | |
4897 | { | |
2a4b3a65 FL |
4898 | for (unsigned i = 0; i < e->args.size(); ++i) |
4899 | replace (e->args[i]); | |
4900 | ||
cdda9521 FL |
4901 | if (stable_fcs.find(e->function) != stable_fcs.end()) |
4902 | { | |
4903 | string name("__stable_"); | |
4904 | name.append(e->function).append("_value"); | |
0e658756 | 4905 | |
cdda9521 FL |
4906 | // Variable potentially not in scope since it is in a sibling block |
4907 | if (scope_vars.find(e->function) == scope_vars.end()) | |
4908 | { | |
4909 | if (new_vars.find(e->function) == new_vars.end()) | |
0e658756 FL |
4910 | { |
4911 | // New variable declaration to store result of function call | |
4912 | vardecl* v = new vardecl; | |
62ac4eaf | 4913 | v->unmangled_name = v->name = name; |
0e658756 FL |
4914 | v->tok = e->tok; |
4915 | v->set_arity(0, e->tok); | |
4916 | v->type = e->type; | |
4917 | if (current_function) | |
4918 | current_function->locals.push_back(v); | |
4919 | else | |
4920 | current_probe->locals.push_back(v); | |
cdda9521 | 4921 | new_vars[e->function] = v; |
0e658756 | 4922 | } |
cdda9521 FL |
4923 | |
4924 | symbol* sym = new symbol; | |
4925 | sym->name = name; | |
4926 | sym->tok = e->tok; | |
4927 | sym->referent = new_vars[e->function]; | |
4928 | sym->type = e->type; | |
4929 | ||
4930 | functioncall* fc = new functioncall; | |
4931 | fc->tok = e->tok; | |
4932 | fc->function = e->function; | |
7b5b30a8 | 4933 | fc->referents = e->referents; |
cdda9521 FL |
4934 | fc->type = e->type; |
4935 | ||
4936 | assignment* a = new assignment; | |
4937 | a->tok = e->tok; | |
4938 | a->op = "="; | |
4939 | a->left = sym; | |
4940 | a->right = fc; | |
4941 | a->type = e->type; | |
4942 | ||
4943 | expr_statement* es = new expr_statement; | |
4944 | es->tok = e->tok; | |
4945 | es->value = a; | |
4946 | ||
5e41c8bc | 4947 | // Store location of the block to put new declaration. |
5e41c8bc FL |
4948 | if (loop_depth != 0) |
4949 | { | |
1aad7ed4 | 4950 | assert(top_scope); |
5e41c8bc FL |
4951 | new_stmts.push_back(make_pair(es,top_scope)); |
4952 | } | |
4953 | else | |
4954 | { | |
1aad7ed4 FL |
4955 | assert(curr_scope); |
4956 | new_stmts.push_back(make_pair(es,curr_scope)); | |
5e41c8bc | 4957 | } |
cdda9521 FL |
4958 | |
4959 | scope_vars.insert(e->function); | |
4960 | ||
4961 | provide(sym); | |
0e658756 | 4962 | } |
cdda9521 FL |
4963 | else |
4964 | { | |
4965 | symbol* sym = new symbol; | |
4966 | sym->name = name; | |
4967 | sym->tok = e->tok; | |
4968 | sym->referent = new_vars[e->function]; | |
4969 | sym->type = e->type; | |
4970 | provide(sym); | |
4971 | } | |
4972 | return; | |
0e658756 FL |
4973 | } |
4974 | ||
4975 | provide(e); | |
4976 | } | |
4977 | ||
cdda9521 FL |
4978 | // Cache stable embedded-c functioncall results and replace |
4979 | // all calls with same name using that value to reduce duplicate | |
1aad7ed4 FL |
4980 | // functioncall overhead. Functioncalls are pulled out of any |
4981 | // top-level loops and put into if/try blocks. | |
cdda9521 | 4982 | void semantic_pass_opt7(systemtap_session& s) |
0e658756 | 4983 | { |
1aad7ed4 FL |
4984 | set<string> stable_fcs; |
4985 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); | |
4986 | it != s.functions.end(); ++it) | |
4987 | { | |
4988 | functiondecl* fn = (*it).second; | |
4989 | stable_analysis sa; | |
4990 | fn->body->visit(&sa); | |
67d60c9f | 4991 | if (sa.stable && fn->formal_args.size() == 0) |
1aad7ed4 FL |
4992 | stable_fcs.insert(fn->name); |
4993 | } | |
4994 | ||
cdda9521 | 4995 | for (vector<derived_probe*>::iterator it = s.probes.begin(); |
0e658756 FL |
4996 | it != s.probes.end(); ++it) |
4997 | { | |
1aad7ed4 | 4998 | stable_functioncall_visitor t(s, stable_fcs); |
0e658756 | 4999 | t.current_probe = *it; |
cdda9521 | 5000 | (*it)->body = t.convert_stmt((*it)->body); |
0e658756 | 5001 | t.replace((*it)->body); |
cdda9521 FL |
5002 | |
5003 | for (vector<pair<expr_statement*,block*> >::iterator st = t.new_stmts.begin(); | |
5004 | st != t.new_stmts.end(); ++st) | |
5005 | st->second->statements.insert(st->second->statements.begin(), st->first); | |
0e658756 | 5006 | } |
cdda9521 FL |
5007 | |
5008 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); | |
5009 | it != s.functions.end(); ++it) | |
0e658756 | 5010 | { |
cdda9521 | 5011 | functiondecl* fn = (*it).second; |
1aad7ed4 | 5012 | stable_functioncall_visitor t(s, stable_fcs); |
cdda9521 FL |
5013 | t.current_function = fn; |
5014 | fn->body = t.convert_stmt(fn->body); | |
5015 | t.replace(fn->body); | |
5016 | ||
5017 | for (vector<pair<expr_statement*,block*> >::iterator st = t.new_stmts.begin(); | |
5018 | st != t.new_stmts.end(); ++st) | |
5019 | st->second->statements.insert(st->second->statements.begin(), st->first); | |
0e658756 FL |
5020 | } |
5021 | } | |
cbfbbf69 FCE |
5022 | |
5023 | static int | |
c214bd6a | 5024 | semantic_pass_optimize1 (systemtap_session& s) |
cbfbbf69 FCE |
5025 | { |
5026 | // In this pass, we attempt to rewrite probe/function bodies to | |
5027 | // eliminate some blatantly unnecessary code. This is run before | |
5028 | // type inference, but after symbol resolution and derived_probe | |
5029 | // creation. We run an outer "relaxation" loop that repeats the | |
5030 | // optimizations until none of them find anything to remove. | |
5031 | ||
5032 | int rc = 0; | |
5033 | ||
bad814e8 CM |
5034 | // Save the old value of suppress_warnings, as we will be changing |
5035 | // it below. | |
5036 | save_and_restore<bool> suppress_warnings(& s.suppress_warnings); | |
5037 | ||
cbfbbf69 | 5038 | bool relaxed_p = false; |
cfd621bc | 5039 | unsigned iterations = 0; |
cbfbbf69 FCE |
5040 | while (! relaxed_p) |
5041 | { | |
e19ebcf7 | 5042 | assert_no_interrupts(); |
49abf162 | 5043 | |
cbfbbf69 FCE |
5044 | relaxed_p = true; // until proven otherwise |
5045 | ||
bad814e8 CM |
5046 | // If the verbosity is high enough, always print warnings (overrides -w), |
5047 | // or if not, always suppress warnings for every itteration after the first. | |
5048 | if(s.verbose > 2) | |
5049 | s.suppress_warnings = false; | |
5050 | else if (iterations > 0) | |
5051 | s.suppress_warnings = true; | |
5052 | ||
c0f56268 JS |
5053 | if (!s.unoptimized) |
5054 | { | |
5055 | semantic_pass_opt1 (s, relaxed_p); | |
5056 | semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0 | |
5057 | semantic_pass_opt3 (s, relaxed_p); | |
5058 | semantic_pass_opt4 (s, relaxed_p); | |
5059 | semantic_pass_opt5 (s, relaxed_p); | |
5060 | } | |
5061 | ||
5062 | // For listing mode, we need const-folding regardless of optimization so | |
5063 | // that @defined expressions can be properly resolved. PR11360 | |
ad12c592 MW |
5064 | // We also want it in case variables are used in if/case expressions, |
5065 | // so enable always. PR11366 | |
4375d018 AJ |
5066 | // rc is incremented if there is an error that got reported. |
5067 | rc += semantic_pass_const_fold (s, relaxed_p); | |
cfd621bc | 5068 | |
7c3feb93 JS |
5069 | if (!s.unoptimized) |
5070 | semantic_pass_dead_control (s, relaxed_p); | |
5071 | ||
cfd621bc | 5072 | iterations ++; |
c214bd6a DS |
5073 | } |
5074 | ||
c214bd6a DS |
5075 | return rc; |
5076 | } | |
5077 | ||
5078 | ||
5079 | static int | |
5080 | semantic_pass_optimize2 (systemtap_session& s) | |
5081 | { | |
5082 | // This is run after type inference. We run an outer "relaxation" | |
5083 | // loop that repeats the optimizations until none of them find | |
5084 | // anything to remove. | |
5085 | ||
5086 | int rc = 0; | |
5087 | ||
bad814e8 CM |
5088 | // Save the old value of suppress_warnings, as we will be changing |
5089 | // it below. | |
5090 | save_and_restore<bool> suppress_warnings(& s.suppress_warnings); | |
5091 | ||
c214bd6a | 5092 | bool relaxed_p = false; |
bad814e8 | 5093 | unsigned iterations = 0; |
c214bd6a DS |
5094 | while (! relaxed_p) |
5095 | { | |
e19ebcf7 | 5096 | assert_no_interrupts(); |
c214bd6a DS |
5097 | relaxed_p = true; // until proven otherwise |
5098 | ||
bad814e8 CM |
5099 | // If the verbosity is high enough, always print warnings (overrides -w), |
5100 | // or if not, always suppress warnings for every itteration after the first. | |
5101 | if(s.verbose > 2) | |
5102 | s.suppress_warnings = false; | |
5103 | else if (iterations > 0) | |
5104 | s.suppress_warnings = true; | |
5105 | ||
c0f56268 JS |
5106 | if (!s.unoptimized) |
5107 | semantic_pass_opt6 (s, relaxed_p); | |
bad814e8 CM |
5108 | |
5109 | iterations++; | |
cbfbbf69 FCE |
5110 | } |
5111 | ||
1aad7ed4 FL |
5112 | if (!s.unoptimized) |
5113 | semantic_pass_opt7(s); | |
5114 | ||
cbfbbf69 FCE |
5115 | return rc; |
5116 | } | |
5117 | ||
5118 | ||
5119 | ||
2b066ec1 FCE |
5120 | // ------------------------------------------------------------------------ |
5121 | // type resolution | |
5122 | ||
66facfa3 JS |
5123 | struct autocast_expanding_visitor: public var_expanding_visitor |
5124 | { | |
5125 | typeresolution_info& ti; | |
389236d5 JS |
5126 | autocast_expanding_visitor (typeresolution_info& ti): ti(ti) {} |
5127 | ||
5128 | void resolve_functioncall (functioncall* fc) | |
5129 | { | |
5130 | // This is a very limited version of semantic_pass_symbols, but we're | |
5131 | // late in the game at this point. We won't get a chance to optimize, | |
5132 | // but for now the only functions we expect are kernel/user_string from | |
5133 | // pretty-printing, which don't need optimization. | |
5134 | ||
5135 | systemtap_session& s = ti.session; | |
5136 | size_t nfiles = s.files.size(); | |
5137 | ||
5138 | symresolution_info sym (s); | |
5139 | sym.current_function = ti.current_function; | |
5140 | sym.current_probe = ti.current_probe; | |
5141 | fc->visit (&sym); | |
5142 | ||
5143 | // NB: synthetic functions get tacked onto the origin file, so we won't | |
5144 | // see them growing s.files[]. Traverse it directly. | |
7b5b30a8 | 5145 | for (unsigned i = 0; i < fc->referents.size(); i++) |
389236d5 | 5146 | { |
7b5b30a8 | 5147 | functiondecl* fd = fc->referents[i]; |
389236d5 JS |
5148 | sym.current_function = fd; |
5149 | sym.current_probe = 0; | |
5150 | fd->body->visit (&sym); | |
5151 | } | |
5152 | ||
5153 | while (nfiles < s.files.size()) | |
5154 | { | |
5155 | stapfile* dome = s.files[nfiles++]; | |
5156 | for (size_t i = 0; i < dome->functions.size(); ++i) | |
5157 | { | |
5158 | functiondecl* fd = dome->functions[i]; | |
5159 | sym.current_function = fd; | |
5160 | sym.current_probe = 0; | |
5161 | fd->body->visit (&sym); | |
5162 | // NB: not adding to s.functions just yet... | |
5163 | } | |
5164 | } | |
5165 | ||
5166 | // Add only the direct functions we need. | |
5167 | functioncall_traversing_visitor ftv; | |
5168 | fc->visit (&ftv); | |
7424f15c JS |
5169 | for (set<functiondecl*>::iterator it = ftv.seen.begin(); |
5170 | it != ftv.seen.end(); ++it) | |
389236d5 JS |
5171 | { |
5172 | functiondecl* fd = *it; | |
5173 | pair<map<string,functiondecl*>::iterator,bool> inserted = | |
5174 | s.functions.insert (make_pair (fd->name, fd)); | |
5175 | if (!inserted.second && inserted.first->second != fd) | |
5176 | throw SEMANTIC_ERROR | |
5177 | (_F("resolved function '%s' conflicts with an existing function", | |
5eb6ecb1 | 5178 | fd->unmangled_name.to_string().c_str()), fc->tok); |
389236d5 JS |
5179 | } |
5180 | } | |
66facfa3 JS |
5181 | |
5182 | void visit_autocast_op (autocast_op* e) | |
5183 | { | |
5184 | const bool lvalue = is_active_lvalue (e); | |
5185 | const exp_type_ptr& details = e->operand->type_details; | |
2107aa37 | 5186 | if (details && !e->saved_conversion_error) |
66facfa3 | 5187 | { |
389236d5 JS |
5188 | functioncall* fc = details->expand (e, lvalue); |
5189 | if (fc) | |
66facfa3 JS |
5190 | { |
5191 | ti.num_newly_resolved++; | |
5192 | ||
389236d5 JS |
5193 | resolve_functioncall (fc); |
5194 | ||
66facfa3 | 5195 | if (lvalue) |
f55efafe | 5196 | provide_lvalue_call (fc); |
66facfa3 | 5197 | |
389236d5 | 5198 | fc->visit (this); |
66facfa3 JS |
5199 | return; |
5200 | } | |
5201 | } | |
5202 | var_expanding_visitor::visit_autocast_op (e); | |
5203 | } | |
5204 | }; | |
2b066ec1 | 5205 | |
357612da AJ |
5206 | |
5207 | struct initial_typeresolution_info : public typeresolution_info | |
5208 | { | |
5209 | initial_typeresolution_info (systemtap_session& s): typeresolution_info(s) | |
5210 | {} | |
5211 | ||
5212 | // these expressions are not supposed to make its way to the typeresolution | |
5213 | // pass. they probably get substituted/replaced, but since this is an initial pass | |
5214 | // and not all substitutions are done, replace the functions that throw errors. | |
dabd71bb MW |
5215 | void visit_target_symbol (target_symbol*) {} |
5216 | void visit_atvar_op (atvar_op*) {} | |
5217 | void visit_defined_op (defined_op*) {} | |
5218 | void visit_entry_op (entry_op*) {} | |
5219 | void visit_cast_op (cast_op*) {} | |
357612da AJ |
5220 | }; |
5221 | ||
4375d018 | 5222 | static int initial_typeres_pass(systemtap_session& s) |
cde4a9fe | 5223 | { |
d897ba7f AJ |
5224 | // minimal type resolution based off of semantic_pass_types(), without |
5225 | // checking for complete type resolutions or autocast expanding | |
357612da | 5226 | initial_typeresolution_info ti(s); |
d897ba7f AJ |
5227 | |
5228 | // Globals never have detailed types. | |
5229 | // If we null them now, then all remaining vardecls can be detailed. | |
5230 | for (unsigned j=0; j<s.globals.size(); j++) | |
5231 | { | |
5232 | vardecl* gd = s.globals[j]; | |
5233 | if (!gd->type_details) | |
5234 | gd->type_details = ti.null_type; | |
5235 | } | |
5236 | ||
357612da | 5237 | ti.assert_resolvability = false; |
cde4a9fe AJ |
5238 | while (1) |
5239 | { | |
5240 | assert_no_interrupts(); | |
5241 | ||
5242 | ti.num_newly_resolved = 0; | |
cde4a9fe AJ |
5243 | ti.num_still_unresolved = 0; |
5244 | ti.num_available_autocasts = 0; | |
5245 | ||
5246 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); | |
5247 | it != s.functions.end(); it++) | |
5248 | { | |
5249 | assert_no_interrupts(); | |
5250 | ||
5251 | functiondecl* fd = it->second; | |
5252 | ti.current_probe = 0; | |
5253 | ti.current_function = fd; | |
5254 | ti.t = pe_unknown; | |
5255 | fd->body->visit (& ti); | |
5256 | } | |
5257 | ||
5258 | for (unsigned j=0; j<s.probes.size(); j++) | |
5259 | { | |
5260 | assert_no_interrupts(); | |
5261 | ||
5262 | derived_probe* pn = s.probes[j]; | |
5263 | ti.current_function = 0; | |
5264 | ti.current_probe = pn; | |
5265 | ti.t = pe_unknown; | |
5266 | pn->body->visit (& ti); | |
5267 | ||
5268 | probe_point* pp = pn->sole_location(); | |
5269 | if (pp->condition) | |
5270 | { | |
5271 | ti.current_function = 0; | |
5272 | ti.current_probe = 0; | |
5273 | ti.t = pe_long; // NB: expected type | |
5274 | pp->condition->visit (& ti); | |
5275 | } | |
5276 | } | |
5277 | if (ti.num_newly_resolved == 0) // converged | |
6540f559 AJ |
5278 | { |
5279 | // take into account that if there are mismatches, we'd want to know | |
5280 | // about them incase they get whisked away, later in this process | |
5281 | if (!ti.assert_resolvability && ti.mismatch_complexity > 0) // found a mismatch!! | |
5282 | { | |
5283 | ti.assert_resolvability = true; // report errors | |
5284 | if (s.verbose > 0) | |
5285 | ti.mismatch_complexity = 1; // print out mismatched but not unresolved type mismatches | |
5286 | } | |
5287 | else | |
5288 | break; | |
5289 | } | |
5290 | else | |
5291 | ti.mismatch_complexity = 0; | |
cde4a9fe | 5292 | } |
4375d018 AJ |
5293 | |
5294 | return s.num_errors(); | |
cde4a9fe AJ |
5295 | } |
5296 | ||
2b066ec1 FCE |
5297 | static int |
5298 | semantic_pass_types (systemtap_session& s) | |
5299 | { | |
5300 | int rc = 0; | |
5301 | ||
5302 | // next pass: type inference | |
5303 | unsigned iterations = 0; | |
5304 | typeresolution_info ti (s); | |
57148ee7 | 5305 | |
eb79eb0a JS |
5306 | // Globals never have detailed types. |
5307 | // If we null them now, then all remaining vardecls can be detailed. | |
5308 | for (unsigned j=0; j<s.globals.size(); j++) | |
5309 | { | |
5310 | vardecl* gd = s.globals[j]; | |
5311 | if (!gd->type_details) | |
5312 | gd->type_details = ti.null_type; | |
5313 | } | |
5314 | ||
2b066ec1 | 5315 | ti.assert_resolvability = false; |
2b066ec1 FCE |
5316 | while (1) |
5317 | { | |
e19ebcf7 | 5318 | assert_no_interrupts(); |
49abf162 | 5319 | |
2b066ec1 | 5320 | iterations ++; |
2b066ec1 FCE |
5321 | ti.num_newly_resolved = 0; |
5322 | ti.num_still_unresolved = 0; | |
66facfa3 | 5323 | ti.num_available_autocasts = 0; |
2b066ec1 | 5324 | |
9e85f932 JL |
5325 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); |
5326 | it != s.functions.end(); it++) | |
96c7f494 FCE |
5327 | try |
5328 | { | |
5329 | assert_no_interrupts(); | |
5330 | ||
5331 | functiondecl* fd = it->second; | |
5332 | ti.current_probe = 0; | |
5333 | ti.current_function = fd; | |
5334 | ti.t = pe_unknown; | |
5335 | fd->body->visit (& ti); | |
5336 | // NB: we don't have to assert a known type for | |
5337 | // functions here, to permit a "void" function. | |
5338 | // The translator phase will omit the "retvalue". | |
5339 | // | |
5340 | // if (fd->type == pe_unknown) | |
5341 | // ti.unresolved (fd->tok); | |
5342 | for (unsigned i=0; i < fd->locals.size(); ++i) | |
5343 | ti.check_local (fd->locals[i]); | |
5344 | ||
5345 | // Check and run the autocast expanding visitor. | |
5346 | if (ti.num_available_autocasts > 0) | |
5347 | { | |
5348 | autocast_expanding_visitor aev (ti); | |
5349 | aev.replace (fd->body); | |
5350 | ti.num_available_autocasts = 0; | |
5351 | } | |
5352 | } | |
5353 | catch (const semantic_error& e) | |
5354 | { | |
5355 | throw SEMANTIC_ERROR(_F("while processing function %s", | |
5eb6ecb1 | 5356 | it->second->unmangled_name.to_string().c_str())).set_chain(e); |
96c7f494 FCE |
5357 | } |
5358 | ||
2b066ec1 | 5359 | for (unsigned j=0; j<s.probes.size(); j++) |
96c7f494 FCE |
5360 | try |
5361 | { | |
5362 | assert_no_interrupts(); | |
5363 | ||
5364 | derived_probe* pn = s.probes[j]; | |
5365 | ti.current_function = 0; | |
5366 | ti.current_probe = pn; | |
5367 | ti.t = pe_unknown; | |
5368 | pn->body->visit (& ti); | |
5369 | for (unsigned i=0; i < pn->locals.size(); ++i) | |
5370 | ti.check_local (pn->locals[i]); | |
5371 | ||
5372 | // Check and run the autocast expanding visitor. | |
5373 | if (ti.num_available_autocasts > 0) | |
5374 | { | |
5375 | autocast_expanding_visitor aev (ti); | |
5376 | aev.replace (pn->body); | |
5377 | ti.num_available_autocasts = 0; | |
5378 | } | |
5379 | ||
5380 | probe_point* pp = pn->sole_location(); | |
5381 | if (pp->condition) | |
5382 | { | |
5383 | ti.current_function = 0; | |
5384 | ti.current_probe = 0; | |
5385 | ti.t = pe_long; // NB: expected type | |
5386 | pp->condition->visit (& ti); | |
5387 | } | |
5388 | } | |
5389 | catch (const semantic_error& e) | |
5390 | { | |
5391 | throw SEMANTIC_ERROR(_F("while processing probe %s", | |
5392 | s.probes[j]->derived_locations(false).c_str())).set_chain(e); | |
5393 | } | |
5394 | ||
2b066ec1 FCE |
5395 | for (unsigned j=0; j<s.globals.size(); j++) |
5396 | { | |
5397 | vardecl* gd = s.globals[j]; | |
5398 | if (gd->type == pe_unknown) | |
5399 | ti.unresolved (gd->tok); | |
bc889c8d CM |
5400 | if(gd->arity == 0 && gd->wrap == true) |
5401 | { | |
96c7f494 | 5402 | throw SEMANTIC_ERROR(_("wrapping not supported for scalars"), gd->tok); |
bc889c8d | 5403 | } |
2b066ec1 | 5404 | } |
57148ee7 | 5405 | |
2b066ec1 | 5406 | if (ti.num_newly_resolved == 0) // converged |
78f6bba6 FCE |
5407 | { |
5408 | if (ti.num_still_unresolved == 0) | |
5409 | break; // successfully | |
5410 | else if (! ti.assert_resolvability) | |
c74ddc54 JL |
5411 | { |
5412 | ti.assert_resolvability = true; // last pass, with error msgs | |
5413 | if (s.verbose > 0) | |
5414 | ti.mismatch_complexity = 0; // print every kind of mismatch | |
5415 | } | |
78f6bba6 FCE |
5416 | else |
5417 | { // unsuccessful conclusion | |
5418 | rc ++; | |
5419 | break; | |
5420 | } | |
5421 | } | |
c74ddc54 JL |
5422 | else |
5423 | ti.mismatch_complexity = 0; // reset for next pass | |
2b066ec1 | 5424 | } |
57148ee7 | 5425 | |
7e41d3dc | 5426 | return rc + s.num_errors(); |
2b066ec1 FCE |
5427 | } |
5428 | ||
5429 | ||
eb79eb0a JS |
5430 | struct exp_type_null : public exp_type_details |
5431 | { | |
5432 | uintptr_t id () const { return 0; } | |
5433 | bool expandable() const { return false; } | |
5434 | functioncall *expand(autocast_op*, bool) { return NULL; } | |
5435 | }; | |
bdef2583 FCE |
5436 | |
5437 | typeresolution_info::typeresolution_info (systemtap_session& s): | |
74fe61bc | 5438 | session(s), num_newly_resolved(0), num_still_unresolved(0), |
c92d3b42 | 5439 | num_available_autocasts(0), |
c74ddc54 | 5440 | assert_resolvability(false), mismatch_complexity(0), |
eb79eb0a JS |
5441 | current_function(0), current_probe(0), t(pe_unknown), |
5442 | null_type(new exp_type_null()) | |
bdef2583 FCE |
5443 | { |
5444 | } | |
5445 | ||
5446 | ||
2b066ec1 FCE |
5447 | void |
5448 | typeresolution_info::visit_literal_number (literal_number* e) | |
5449 | { | |
5450 | assert (e->type == pe_long); | |
5451 | if ((t == e->type) || (t == pe_unknown)) | |
5452 | return; | |
5453 | ||
18bac841 | 5454 | mismatch (e->tok, t, e->type); |
2b066ec1 FCE |
5455 | } |
5456 | ||
5457 | ||
5458 | void | |
5459 | typeresolution_info::visit_literal_string (literal_string* e) | |
5460 | { | |
5461 | assert (e->type == pe_string); | |
5462 | if ((t == e->type) || (t == pe_unknown)) | |
5463 | return; | |
5464 | ||
18bac841 | 5465 | mismatch (e->tok, t, e->type); |
2b066ec1 FCE |
5466 | } |
5467 | ||
5468 | ||
5469 | void | |
5470 | typeresolution_info::visit_logical_or_expr (logical_or_expr *e) | |
5471 | { | |
5472 | visit_binary_expression (e); | |
5473 | } | |
5474 | ||
5475 | ||
5476 | void | |
5477 | typeresolution_info::visit_logical_and_expr (logical_and_expr *e) | |
5478 | { | |
5479 | visit_binary_expression (e); | |
5480 | } | |
5481 | ||
93daaca8 SM |
5482 | void |
5483 | typeresolution_info::visit_regex_query (regex_query *e) | |
5484 | { | |
5485 | // NB: result of regex query is an integer! | |
5486 | if (t == pe_stats || t == pe_string) | |
5487 | invalid (e->tok, t); | |
5488 | ||
5489 | t = pe_string; | |
5490 | e->left->visit (this); | |
5491 | t = pe_string; | |
5492 | e->right->visit (this); // parser ensures this is a literal known at compile time | |
5493 | ||
5494 | if (e->type == pe_unknown) | |
5495 | { | |
5496 | e->type = pe_long; | |
5497 | resolved (e->tok, e->type); | |
5498 | } | |
5499 | } | |
5500 | ||
2b066ec1 FCE |
5501 | |
5502 | void | |
5503 | typeresolution_info::visit_comparison (comparison *e) | |
5504 | { | |
d5d7c2cc | 5505 | // NB: result of any comparison is an integer! |
553d27a5 FCE |
5506 | if (t == pe_stats || t == pe_string) |
5507 | invalid (e->tok, t); | |
5508 | ||
5509 | t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown; | |
5510 | e->left->visit (this); | |
5511 | t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown; | |
5512 | e->right->visit (this); | |
57148ee7 | 5513 | |
553d27a5 FCE |
5514 | if (e->left->type != pe_unknown && |
5515 | e->right->type != pe_unknown && | |
5516 | e->left->type != e->right->type) | |
18bac841 | 5517 | mismatch (e); |
57148ee7 | 5518 | |
553d27a5 FCE |
5519 | if (e->type == pe_unknown) |
5520 | { | |
5521 | e->type = pe_long; | |
5522 | resolved (e->tok, e->type); | |
5523 | } | |
2b066ec1 FCE |
5524 | } |
5525 | ||
5526 | ||
5527 | void | |
5528 | typeresolution_info::visit_concatenation (concatenation *e) | |
5529 | { | |
553d27a5 FCE |
5530 | if (t != pe_unknown && t != pe_string) |
5531 | invalid (e->tok, t); | |
5532 | ||
5533 | t = pe_string; | |
5534 | e->left->visit (this); | |
5535 | t = pe_string; | |
5536 | e->right->visit (this); | |
5537 | ||
5538 | if (e->type == pe_unknown) | |
5539 | { | |
5540 | e->type = pe_string; | |
5541 | resolved (e->tok, e->type); | |
5542 | } | |
2b066ec1 FCE |
5543 | } |
5544 | ||
5545 | ||
2b066ec1 FCE |
5546 | void |
5547 | typeresolution_info::visit_assignment (assignment *e) | |
5548 | { | |
553d27a5 FCE |
5549 | if (t == pe_stats) |
5550 | invalid (e->tok, t); | |
2b066ec1 | 5551 | |
2b066ec1 FCE |
5552 | if (e->op == "<<<") // stats aggregation |
5553 | { | |
553d27a5 FCE |
5554 | if (t == pe_string) |
5555 | invalid (e->tok, t); | |
5556 | ||
2b066ec1 FCE |
5557 | t = pe_stats; |
5558 | e->left->visit (this); | |
5559 | t = pe_long; | |
5560 | e->right->visit (this); | |
57b73400 GH |
5561 | if (e->type == pe_unknown || |
5562 | e->type == pe_stats) | |
2b066ec1 FCE |
5563 | { |
5564 | e->type = pe_long; | |
5565 | resolved (e->tok, e->type); | |
5566 | } | |
5567 | } | |
57b73400 GH |
5568 | |
5569 | else if (e->left->type == pe_stats) | |
5570 | invalid (e->left->tok, e->left->type); | |
5571 | ||
5572 | else if (e->right->type == pe_stats) | |
5573 | invalid (e->right->tok, e->right->type); | |
5574 | ||
553d27a5 | 5575 | else if (e->op == "+=" || // numeric only |
d5d7c2cc FCE |
5576 | e->op == "-=" || |
5577 | e->op == "*=" || | |
5578 | e->op == "/=" || | |
5579 | e->op == "%=" || | |
5580 | e->op == "&=" || | |
5581 | e->op == "^=" || | |
5582 | e->op == "|=" || | |
5583 | e->op == "<<=" || | |
5584 | e->op == ">>=" || | |
553d27a5 | 5585 | false) |
2b066ec1 | 5586 | { |
553d27a5 | 5587 | visit_binary_expression (e); |
2b066ec1 | 5588 | } |
d5d7c2cc FCE |
5589 | else if (e->op == ".=" || // string only |
5590 | false) | |
5591 | { | |
5592 | if (t == pe_long || t == pe_stats) | |
5593 | invalid (e->tok, t); | |
5594 | ||
5595 | t = pe_string; | |
5596 | e->left->visit (this); | |
5597 | t = pe_string; | |
5598 | e->right->visit (this); | |
5599 | if (e->type == pe_unknown) | |
5600 | { | |
5601 | e->type = pe_string; | |
5602 | resolved (e->tok, e->type); | |
5603 | } | |
5604 | } | |
5605 | else if (e->op == "=") // overloaded = for string & numeric operands | |
2b066ec1 | 5606 | { |
553d27a5 | 5607 | // logic similar to ternary_expression |
2b066ec1 | 5608 | exp_type sub_type = t; |
553d27a5 FCE |
5609 | |
5610 | // Infer types across the l/r values | |
5611 | if (sub_type == pe_unknown && e->type != pe_unknown) | |
2b066ec1 | 5612 | sub_type = e->type; |
553d27a5 FCE |
5613 | |
5614 | t = (sub_type != pe_unknown) ? sub_type : | |
5615 | (e->right->type != pe_unknown) ? e->right->type : | |
5616 | pe_unknown; | |
2b066ec1 | 5617 | e->left->visit (this); |
553d27a5 FCE |
5618 | t = (sub_type != pe_unknown) ? sub_type : |
5619 | (e->left->type != pe_unknown) ? e->left->type : | |
5620 | pe_unknown; | |
2b066ec1 | 5621 | e->right->visit (this); |
57148ee7 | 5622 | |
553d27a5 | 5623 | if ((sub_type != pe_unknown) && (e->type == pe_unknown)) |
2b066ec1 FCE |
5624 | { |
5625 | e->type = sub_type; | |
5626 | resolved (e->tok, e->type); | |
5627 | } | |
553d27a5 | 5628 | if ((sub_type == pe_unknown) && (e->left->type != pe_unknown)) |
2b066ec1 FCE |
5629 | { |
5630 | e->type = e->left->type; | |
5631 | resolved (e->tok, e->type); | |
5632 | } | |
553d27a5 FCE |
5633 | |
5634 | if (e->left->type != pe_unknown && | |
5635 | e->right->type != pe_unknown && | |
5636 | e->left->type != e->right->type) | |
18bac841 | 5637 | mismatch (e); |
d02548c0 | 5638 | |
eb79eb0a JS |
5639 | // Propagate type details from the RHS to the assignment |
5640 | if (e->type == e->right->type && | |
5641 | e->right->type_details && !e->type_details) | |
5642 | resolved_details(e->right->type_details, e->type_details); | |
5643 | ||
5644 | // Propagate type details from the assignment to the LHS | |
5645 | if (e->type == e->left->type && e->type_details) | |
5646 | { | |
5647 | if (e->left->type_details && | |
5648 | *e->left->type_details != *e->type_details && | |
5649 | *e->left->type_details != *null_type) | |
5650 | resolved_details(null_type, e->left->type_details); | |
5651 | else if (!e->left->type_details) | |
5652 | resolved_details(e->type_details, e->left->type_details); | |
5653 | } | |
553d27a5 | 5654 | } |
d5d7c2cc | 5655 | else |
47d349b1 | 5656 | throw SEMANTIC_ERROR (_("unsupported assignment operator ") + (string)e->op); |
553d27a5 FCE |
5657 | } |
5658 | ||
5659 | ||
7d902887 FCE |
5660 | void |
5661 | typeresolution_info::visit_embedded_expr (embedded_expr *e) | |
5662 | { | |
5663 | if (e->type == pe_unknown) | |
5664 | { | |
5665 | if (e->code.find ("/* string */") != string::npos) | |
5666 | e->type = pe_string; | |
5667 | else // if (e->code.find ("/* long */") != string::npos) | |
5668 | e->type = pe_long; | |
5669 | ||
5670 | resolved (e->tok, e->type); | |
5671 | } | |
5672 | } | |
5673 | ||
5674 | ||
553d27a5 FCE |
5675 | void |
5676 | typeresolution_info::visit_binary_expression (binary_expression* e) | |
5677 | { | |
5678 | if (t == pe_stats || t == pe_string) | |
5679 | invalid (e->tok, t); | |
5680 | ||
5681 | t = pe_long; | |
5682 | e->left->visit (this); | |
5683 | t = pe_long; | |
5684 | e->right->visit (this); | |
5685 | ||
5686 | if (e->left->type != pe_unknown && | |
5687 | e->right->type != pe_unknown && | |
5688 | e->left->type != e->right->type) | |
18bac841 | 5689 | mismatch (e); |
57148ee7 | 5690 | |
553d27a5 FCE |
5691 | if (e->type == pe_unknown) |
5692 | { | |
5693 | e->type = pe_long; | |
5694 | resolved (e->tok, e->type); | |
2b066ec1 FCE |
5695 | } |
5696 | } | |
5697 | ||
5698 | ||
5699 | void | |
5700 | typeresolution_info::visit_pre_crement (pre_crement *e) | |
5701 | { | |
5702 | visit_unary_expression (e); | |
5703 | } | |
5704 | ||
5705 | ||
5706 | void | |
5707 | typeresolution_info::visit_post_crement (post_crement *e) | |
5708 | { | |
5709 | visit_unary_expression (e); | |
5710 | } | |
5711 | ||
5712 | ||
5713 | void | |
5714 | typeresolution_info::visit_unary_expression (unary_expression* e) | |
5715 | { | |
553d27a5 FCE |
5716 | if (t == pe_stats || t == pe_string) |
5717 | invalid (e->tok, t); | |
5718 | ||
2b066ec1 FCE |
5719 | t = pe_long; |
5720 | e->operand->visit (this); | |
5721 | ||
553d27a5 | 5722 | if (e->type == pe_unknown) |
2b066ec1 FCE |
5723 | { |
5724 | e->type = pe_long; | |
5725 | resolved (e->tok, e->type); | |
5726 | } | |
5727 | } | |
5728 | ||
5729 | ||
2b066ec1 FCE |
5730 | void |
5731 | typeresolution_info::visit_ternary_expression (ternary_expression* e) | |
5732 | { | |
5733 | exp_type sub_type = t; | |
5734 | ||
5735 | t = pe_long; | |
5736 | e->cond->visit (this); | |
5737 | ||
553d27a5 | 5738 | // Infer types across the true/false arms of the ternary expression. |
2b066ec1 FCE |
5739 | |
5740 | if (sub_type == pe_unknown && e->type != pe_unknown) | |
5741 | sub_type = e->type; | |
5742 | t = sub_type; | |
5743 | e->truevalue->visit (this); | |
5744 | t = sub_type; | |
5745 | e->falsevalue->visit (this); | |
5746 | ||
5747 | if ((sub_type == pe_unknown) && (e->type != pe_unknown)) | |
5748 | ; // already resolved | |
5749 | else if ((sub_type != pe_unknown) && (e->type == pe_unknown)) | |
5750 | { | |
5751 | e->type = sub_type; | |
5752 | resolved (e->tok, e->type); | |
5753 | } | |
5754 | else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown)) | |
5755 | { | |
5756 | e->type = e->truevalue->type; | |
5757 | resolved (e->tok, e->type); | |
5758 | } | |
5759 | else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown)) | |
5760 | { | |
5761 | e->type = e->falsevalue->type; | |
5762 | resolved (e->tok, e->type); | |
5763 | } | |
5764 | else if (e->type != sub_type) | |
5765 | mismatch (e->tok, sub_type, e->type); | |
eb79eb0a JS |
5766 | |
5767 | // Propagate type details from both true/false branches | |
5768 | if (!e->type_details && | |
5769 | e->type == e->truevalue->type && e->type == e->falsevalue->type && | |
5770 | e->truevalue->type_details && e->falsevalue->type_details && | |
5771 | *e->truevalue->type_details == *e->falsevalue->type_details) | |
5772 | resolved_details(e->truevalue->type_details, e->type_details); | |
2b066ec1 FCE |
5773 | } |
5774 | ||
5775 | ||
5776 | template <class Referrer, class Referent> | |
5777 | void resolve_2types (Referrer* referrer, Referent* referent, | |
31966088 | 5778 | typeresolution_info* r, exp_type t, bool accept_unknown = false) |
2b066ec1 FCE |
5779 | { |
5780 | exp_type& re_type = referrer->type; | |
5781 | const token* re_tok = referrer->tok; | |
5782 | exp_type& te_type = referent->type; | |
2b066ec1 FCE |
5783 | |
5784 | if (t != pe_unknown && re_type == t && re_type == te_type) | |
5785 | ; // do nothing: all three e->types in agreement | |
5786 | else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type) | |
5787 | ; // do nothing: two known e->types in agreement | |
5788 | else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type) | |
18bac841 | 5789 | r->mismatch (re_tok, re_type, referent); // referrer-referent |
2b066ec1 | 5790 | else if (re_type != pe_unknown && t != pe_unknown && re_type != t) |
18bac841 | 5791 | r->mismatch (re_tok, t, referent); // referrer-t |
2b066ec1 | 5792 | else if (te_type != pe_unknown && t != pe_unknown && te_type != t) |
18bac841 | 5793 | r->mismatch (re_tok, t, referent); // referent-t |
2b066ec1 FCE |
5794 | else if (re_type == pe_unknown && t != pe_unknown) |
5795 | { | |
5796 | // propagate from upstream | |
5797 | re_type = t; | |
5798 | r->resolved (re_tok, re_type); | |
5799 | // catch re_type/te_type mismatch later | |
5800 | } | |
5801 | else if (re_type == pe_unknown && te_type != pe_unknown) | |
5802 | { | |
5803 | // propagate from referent | |
5804 | re_type = te_type; | |
5805 | r->resolved (re_tok, re_type); | |
5806 | // catch re_type/t mismatch later | |
5807 | } | |
5808 | else if (re_type != pe_unknown && te_type == pe_unknown) | |
5809 | { | |
5810 | // propagate to referent | |
5811 | te_type = re_type; | |
18bac841 | 5812 | r->resolved (re_tok, re_type, referent); |
2b066ec1 FCE |
5813 | // catch re_type/t mismatch later |
5814 | } | |
31966088 | 5815 | else if (! accept_unknown) |
2b066ec1 FCE |
5816 | r->unresolved (re_tok); |
5817 | } | |
5818 | ||
5819 | ||
5820 | void | |
5821 | typeresolution_info::visit_symbol (symbol* e) | |
5822 | { | |
017b0053 | 5823 | if (e->referent == 0) |
47d349b1 | 5824 | throw SEMANTIC_ERROR (_F("internal error: unresolved symbol '%s'", |
7371cd19 | 5825 | e->name.to_string().c_str()), e->tok); |
017b0053 | 5826 | |
d02548c0 | 5827 | resolve_2types (e, e->referent, this, t); |
eb79eb0a JS |
5828 | |
5829 | if (e->type == e->referent->type) | |
5830 | { | |
5831 | // If both have type details, then they either must agree; | |
5832 | // otherwise force them both to null. | |
5833 | if (e->type_details && e->referent->type_details && | |
5834 | *e->type_details != *e->referent->type_details) | |
5835 | { | |
5836 | resolved_details(null_type, e->type_details); | |
5837 | resolved_details(null_type, e->referent->type_details); | |
5838 | } | |
5839 | else if (e->type_details && !e->referent->type_details) | |
5840 | resolved_details(e->type_details, e->referent->type_details); | |
5841 | else if (!e->type_details && e->referent->type_details) | |
5842 | resolved_details(e->referent->type_details, e->type_details); | |
5843 | } | |
2b066ec1 FCE |
5844 | } |
5845 | ||
5846 | ||
d7f3e0c5 GH |
5847 | void |
5848 | typeresolution_info::visit_target_symbol (target_symbol* e) | |
5849 | { | |
cbfbbf69 FCE |
5850 | // This occurs only if a target symbol was not resolved over in |
5851 | // tapset.cxx land, that error was properly suppressed, and the | |
5852 | // later unused-expression-elimination pass didn't get rid of it | |
5853 | // either. So we have a target symbol that is believed to be of | |
5854 | // genuine use, yet unresolved by the provider. | |
ba6f838d FCE |
5855 | |
5856 | if (session.verbose > 2) | |
5857 | { | |
4af765b2 | 5858 | clog << _("Resolution problem with "); |
ba6f838d FCE |
5859 | if (current_function) |
5860 | { | |
5861 | clog << "function " << current_function->name << endl; | |
5862 | current_function->body->print (clog); | |
5863 | clog << endl; | |
5864 | } | |
5865 | else if (current_probe) | |
5866 | { | |
da2df842 | 5867 | clog << "probe " << *current_probe->sole_location() << endl; |
ba6f838d FCE |
5868 | current_probe->body->print (clog); |
5869 | clog << endl; | |
5870 | } | |
57148ee7 | 5871 | else |
4af765b2 LB |
5872 | //TRANSLATORS: simply saying not an issue with a probe or function |
5873 | clog << _("other") << endl; | |
ba6f838d FCE |
5874 | } |
5875 | ||
9b48ce88 FCE |
5876 | if (e->saved_conversion_error) |
5877 | throw (* (e->saved_conversion_error)); | |
5878 | else | |
dc09353a | 5879 | throw SEMANTIC_ERROR(_("unresolved target-symbol expression"), e->tok); |
d7f3e0c5 GH |
5880 | } |
5881 | ||
5882 | ||
bd1fcbad YZ |
5883 | void |
5884 | typeresolution_info::visit_atvar_op (atvar_op* e) | |
5885 | { | |
5886 | // This occurs only if an @var() was not resolved over in | |
5887 | // tapset.cxx land, that error was properly suppressed, and the | |
5888 | // later unused-expression-elimination pass didn't get rid of it | |
5889 | // either. So we have an @var() that is believed to be of | |
5890 | // genuine use, yet unresolved by the provider. | |
5891 | ||
5892 | if (session.verbose > 2) | |
5893 | { | |
5894 | clog << _("Resolution problem with "); | |
5895 | if (current_function) | |
5896 | { | |
5897 | clog << "function " << current_function->name << endl; | |
5898 | current_function->body->print (clog); | |
5899 | clog << endl; | |
5900 | } | |
5901 | else if (current_probe) | |
5902 | { | |
5903 | clog << "probe " << *current_probe->sole_location() << endl; | |
5904 | current_probe->body->print (clog); | |
5905 | clog << endl; | |
5906 | } | |
5907 | else | |
5908 | //TRANSLATORS: simply saying not an issue with a probe or function | |
5909 | clog << _("other") << endl; | |
5910 | } | |
5911 | ||
5912 | if (e->saved_conversion_error) | |
5913 | throw (* (e->saved_conversion_error)); | |
5914 | else | |
dc09353a | 5915 | throw SEMANTIC_ERROR(_("unresolved @var() expression"), e->tok); |
bd1fcbad YZ |
5916 | } |
5917 | ||
5918 | ||
30263a73 FCE |
5919 | void |
5920 | typeresolution_info::visit_defined_op (defined_op* e) | |
5921 | { | |
dc09353a | 5922 | throw SEMANTIC_ERROR(_("unexpected @defined"), e->tok); |
30263a73 FCE |
5923 | } |
5924 | ||
5925 | ||
8cc799a5 JS |
5926 | void |
5927 | typeresolution_info::visit_entry_op (entry_op* e) | |
5928 | { | |
dc09353a | 5929 | throw SEMANTIC_ERROR(_("@entry is only valid in .return probes"), e->tok); |
8cc799a5 JS |
5930 | } |
5931 | ||
5932 | ||
9b5af295 JS |
5933 | void |
5934 | typeresolution_info::visit_cast_op (cast_op* e) | |
5935 | { | |
5936 | // Like target_symbol, a cast_op shouldn't survive this far | |
5937 | // unless it was not resolved and its value is really needed. | |
5938 | if (e->saved_conversion_error) | |
5939 | throw (* (e->saved_conversion_error)); | |
5940 | else | |
47d349b1 | 5941 | throw SEMANTIC_ERROR(_F("type definition '%s' not found in '%s'", |
7371cd19 JS |
5942 | e->type_name.to_string().c_str(), |
5943 | e->module.to_string().c_str()), e->tok); | |
9b5af295 JS |
5944 | } |
5945 | ||
5946 | ||
251707c8 JS |
5947 | void |
5948 | typeresolution_info::visit_autocast_op (autocast_op* e) | |
5949 | { | |
5950 | // Like cast_op, a implicit autocast_op shouldn't survive this far | |
5951 | // unless it was not resolved and its value is really needed. | |
2107aa37 | 5952 | if (assert_resolvability && e->saved_conversion_error) |
251707c8 | 5953 | throw (* (e->saved_conversion_error)); |
66facfa3 | 5954 | else if (assert_resolvability) |
251707c8 | 5955 | throw SEMANTIC_ERROR(_("unknown type in dereference"), e->tok); |
66facfa3 JS |
5956 | |
5957 | t = pe_long; | |
5958 | e->operand->visit (this); | |
5959 | ||
5960 | num_still_unresolved++; | |
eb79eb0a JS |
5961 | if (e->operand->type_details && |
5962 | e->operand->type_details->expandable()) | |
66facfa3 | 5963 | num_available_autocasts++; |
251707c8 JS |
5964 | } |
5965 | ||
5966 | ||
3689db05 SC |
5967 | void |
5968 | typeresolution_info::visit_perf_op (perf_op* e) | |
5969 | { | |
5970 | // A perf_op should already be resolved | |
5971 | if (t == pe_stats || t == pe_string) | |
5972 | invalid (e->tok, t); | |
5973 | ||
ad583484 FCE |
5974 | e->type = pe_long; |
5975 | ||
5976 | // (There is no real need to visit our operand - by parser | |
5977 | // construction, it's always a string literal, with its type already | |
5978 | // set.) | |
5979 | t = pe_string; | |
3689db05 SC |
5980 | e->operand->visit (this); |
5981 | } | |
5982 | ||
5983 | ||
2b066ec1 FCE |
5984 | void |
5985 | typeresolution_info::visit_arrayindex (arrayindex* e) | |
5986 | { | |
2b066ec1 | 5987 | |
d02548c0 GH |
5988 | symbol *array = NULL; |
5989 | hist_op *hist = NULL; | |
5990 | classify_indexable(e->base, array, hist); | |
57148ee7 | 5991 | |
d02548c0 GH |
5992 | // Every hist_op has type [int]:int, that is to say, every hist_op |
5993 | // is a pseudo-one-dimensional integer array type indexed by | |
5994 | // integers (bucket numbers). | |
5995 | ||
5996 | if (hist) | |
5997 | { | |
5998 | if (e->indexes.size() != 1) | |
5999 | unresolved (e->tok); | |
6000 | t = pe_long; | |
6001 | e->indexes[0]->visit (this); | |
6002 | if (e->indexes[0]->type != pe_long) | |
6003 | unresolved (e->tok); | |
a4636912 | 6004 | hist->visit (this); |
1bbeef03 GH |
6005 | if (e->type != pe_long) |
6006 | { | |
6007 | e->type = pe_long; | |
18bac841 | 6008 | resolved (e->tok, e->type); |
1bbeef03 | 6009 | } |
d02548c0 GH |
6010 | return; |
6011 | } | |
6012 | ||
6013 | // Now we are left with "normal" map inference and index checking. | |
6014 | ||
6015 | assert (array); | |
6016 | assert (array->referent != 0); | |
6017 | resolve_2types (e, array->referent, this, t); | |
2b066ec1 FCE |
6018 | |
6019 | // now resolve the array indexes | |
69c68955 FCE |
6020 | |
6021 | // if (e->referent->index_types.size() == 0) | |
6022 | // // redesignate referent as array | |
6023 | // e->referent->set_arity (e->indexes.size ()); | |
2b066ec1 | 6024 | |
d02548c0 | 6025 | if (e->indexes.size() != array->referent->index_types.size()) |
2b066ec1 FCE |
6026 | unresolved (e->tok); // symbol resolution should prevent this |
6027 | else for (unsigned i=0; i<e->indexes.size(); i++) | |
6028 | { | |
45af9d1b | 6029 | if (e->indexes[i]) |
2b066ec1 | 6030 | { |
45af9d1b AJ |
6031 | expression* ee = e->indexes[i]; |
6032 | exp_type& ft = array->referent->index_types [i]; | |
6033 | t = ft; | |
6034 | ee->visit (this); | |
6035 | exp_type at = ee->type; | |
6036 | ||
6037 | if ((at == pe_string || at == pe_long) && ft == pe_unknown) | |
6038 | { | |
6039 | // propagate to formal type | |
6040 | ft = at; | |
6041 | resolved (ee->tok, ft, array->referent, i); | |
6042 | } | |
6043 | if (at == pe_stats) | |
6044 | invalid (ee->tok, at); | |
6045 | if (ft == pe_stats) | |
6046 | invalid (ee->tok, ft); | |
6047 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
6048 | mismatch (ee->tok, ee->type, array->referent, i); | |
6049 | if (at == pe_unknown) | |
6050 | unresolved (ee->tok); | |
2b066ec1 | 6051 | } |
2b066ec1 FCE |
6052 | } |
6053 | } | |
6054 | ||
6055 | ||
6056 | void | |
6057 | typeresolution_info::visit_functioncall (functioncall* e) | |
6058 | { | |
7b5b30a8 | 6059 | if (e->referents.empty()) |
017b0053 | 6060 | throw SEMANTIC_ERROR (_F("internal error: unresolved function call to '%s'", |
7371cd19 | 6061 | e->function.to_string().c_str()), e->tok); |
2b066ec1 | 6062 | |
c0d0d623 | 6063 | exp_type original = t; |
7b5b30a8 FL |
6064 | for (unsigned fd = 0; fd < e->referents.size(); fd++) |
6065 | { | |
c0d0d623 | 6066 | t = original; // type may be changed by overloaded functions so restore it |
7b5b30a8 FL |
6067 | functiondecl* referent = e->referents[fd]; |
6068 | resolve_2types (e, referent, this, t, true); // accept unknown type | |
2b066ec1 | 6069 | |
7b5b30a8 FL |
6070 | if (e->type == pe_stats) |
6071 | invalid (e->tok, e->type); | |
c3ed664e | 6072 | |
7b5b30a8 FL |
6073 | const exp_type_ptr& func_type = referent->type_details; |
6074 | if (func_type && referent->type == e->type | |
6075 | && (!e->type_details || *func_type != *e->type_details)) | |
6076 | resolved_details(referent->type_details, e->type_details); | |
57148ee7 | 6077 | |
7b5b30a8 FL |
6078 | // now resolve the function parameters |
6079 | if (e->args.size() != referent->formal_args.size()) | |
6080 | unresolved (e->tok); // symbol resolution should prevent this | |
6081 | else for (unsigned i=0; i<e->args.size(); i++) | |
2b066ec1 | 6082 | { |
7b5b30a8 FL |
6083 | expression* ee = e->args[i]; |
6084 | exp_type& ft = referent->formal_args[i]->type; | |
6085 | const token* fe_tok = referent->formal_args[i]->tok; | |
6086 | t = ft; | |
6087 | ee->visit (this); | |
6088 | exp_type at = ee->type; | |
6089 | ||
6090 | if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown) | |
6091 | { | |
6092 | // propagate to formal arg | |
6093 | ft = at; | |
6094 | resolved (ee->tok, ft, referent->formal_args[i], i); | |
6095 | } | |
6096 | if (at == pe_stats) | |
6097 | invalid (ee->tok, at); | |
6098 | if (ft == pe_stats) | |
6099 | invalid (fe_tok, ft); | |
6100 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
6101 | mismatch (ee->tok, ee->type, referent->formal_args[i], i); | |
6102 | if (at == pe_unknown) | |
6103 | unresolved (ee->tok); | |
2b066ec1 | 6104 | } |
2b066ec1 FCE |
6105 | } |
6106 | } | |
6107 | ||
6108 | ||
6109 | void | |
6110 | typeresolution_info::visit_block (block* e) | |
6111 | { | |
6112 | for (unsigned i=0; i<e->statements.size(); i++) | |
6113 | { | |
1cda9c44 JS |
6114 | t = pe_unknown; |
6115 | e->statements[i]->visit (this); | |
2b066ec1 FCE |
6116 | } |
6117 | } | |
6118 | ||
6119 | ||
f4fe2e93 FCE |
6120 | void |
6121 | typeresolution_info::visit_try_block (try_block* e) | |
6122 | { | |
6123 | if (e->try_block) | |
6124 | e->try_block->visit (this); | |
6125 | if (e->catch_error_var) | |
6126 | { | |
6127 | t = pe_string; | |
6128 | e->catch_error_var->visit (this); | |
6129 | } | |
6130 | if (e->catch_block) | |
6131 | e->catch_block->visit (this); | |
6132 | } | |
6133 | ||
6134 | ||
54dfabe9 | 6135 | void |
6a80494e | 6136 | typeresolution_info::visit_embeddedcode (embeddedcode* s) |
54dfabe9 | 6137 | { |
6a80494e FCE |
6138 | // PR11573. If we have survived thus far with a piece of embedded |
6139 | // code that requires uprobes, we need to track this. | |
6140 | // | |
6141 | // This is an odd place for this check, as opposed | |
6142 | // to a separate 'optimization' pass, or c_unparser::visit_embeddedcode | |
6143 | // over yonder in pass 3. However, we want to do it during pass 2 so | |
6144 | // that cached sessions also get the uprobes treatment. | |
26c2e4c2 SM |
6145 | if (! session.need_uprobes |
6146 | && s->code.find("/* pragma:uprobes */") != string::npos) | |
6a80494e FCE |
6147 | { |
6148 | if (session.verbose > 2) | |
4af765b2 | 6149 | clog << _("Activating uprobes support because /* pragma:uprobes */ seen.") << endl; |
6a80494e FCE |
6150 | session.need_uprobes = true; |
6151 | } | |
26c2e4c2 SM |
6152 | |
6153 | // PR15065. Likewise, we need to detect /* pragma:tagged_dfa */ | |
6154 | // before the gen_dfa_table pass. Again, the typechecking part of | |
6155 | // pass 2 is a good place for this. | |
6156 | if (! session.need_tagged_dfa | |
6157 | && s->code.find("/* pragma:tagged_dfa */") != string::npos) | |
6158 | { | |
112e9e2b SM |
6159 | // if (session.verbose > 2) |
6160 | // clog << _F("Turning on DFA subexpressions, pragma:tagged_dfa found in %s", | |
6161 | // current_function->name.c_str()) << endl; | |
6162 | // session.need_tagged_dfa = true; | |
dc09353a | 6163 | throw SEMANTIC_ERROR (_("Tagged DFA support is not yet available"), s->tok); |
26c2e4c2 | 6164 | } |
54dfabe9 FCE |
6165 | } |
6166 | ||
6167 | ||
2b066ec1 FCE |
6168 | void |
6169 | typeresolution_info::visit_if_statement (if_statement* e) | |
6170 | { | |
6171 | t = pe_long; | |
6172 | e->condition->visit (this); | |
6173 | ||
6174 | t = pe_unknown; | |
6175 | e->thenblock->visit (this); | |
6176 | ||
6177 | if (e->elseblock) | |
6178 | { | |
6179 | t = pe_unknown; | |
6180 | e->elseblock->visit (this); | |
6181 | } | |
6182 | } | |
6183 | ||
6184 | ||
6185 | void | |
6186 | typeresolution_info::visit_for_loop (for_loop* e) | |
6187 | { | |
6188 | t = pe_unknown; | |
cbfbbf69 | 6189 | if (e->init) e->init->visit (this); |
2b066ec1 FCE |
6190 | t = pe_long; |
6191 | e->cond->visit (this); | |
6192 | t = pe_unknown; | |
57148ee7 | 6193 | if (e->incr) e->incr->visit (this); |
2b066ec1 | 6194 | t = pe_unknown; |
57148ee7 | 6195 | e->block->visit (this); |
2b066ec1 FCE |
6196 | } |
6197 | ||
6198 | ||
69c68955 FCE |
6199 | void |
6200 | typeresolution_info::visit_foreach_loop (foreach_loop* e) | |
6201 | { | |
6202 | // See also visit_arrayindex. | |
6203 | // This is different in that, being a statement, we can't assign | |
6204 | // a type to the outer array, only propagate to/from the indexes | |
6205 | ||
6206 | // if (e->referent->index_types.size() == 0) | |
6207 | // // redesignate referent as array | |
6208 | // e->referent->set_arity (e->indexes.size ()); | |
6209 | ||
c261711d | 6210 | exp_type wanted_value = pe_unknown; |
d02548c0 GH |
6211 | symbol *array = NULL; |
6212 | hist_op *hist = NULL; | |
6213 | classify_indexable(e->base, array, hist); | |
69c68955 | 6214 | |
d02548c0 | 6215 | if (hist) |
57148ee7 | 6216 | { |
d02548c0 GH |
6217 | if (e->indexes.size() != 1) |
6218 | unresolved (e->tok); | |
6219 | t = pe_long; | |
6220 | e->indexes[0]->visit (this); | |
6221 | if (e->indexes[0]->type != pe_long) | |
6222 | unresolved (e->tok); | |
a4636912 | 6223 | hist->visit (this); |
c261711d | 6224 | wanted_value = pe_long; |
d02548c0 GH |
6225 | } |
6226 | else | |
6227 | { | |
57148ee7 | 6228 | assert (array); |
d02548c0 GH |
6229 | if (e->indexes.size() != array->referent->index_types.size()) |
6230 | unresolved (e->tok); // symbol resolution should prevent this | |
3040bf3a AJ |
6231 | else |
6232 | { | |
6233 | for (unsigned i=0; i<e->indexes.size(); i++) | |
6234 | { | |
6235 | expression* ee = e->indexes[i]; | |
6236 | exp_type& ft = array->referent->index_types [i]; | |
6237 | t = ft; | |
6238 | ee->visit (this); | |
6239 | exp_type at = ee->type; | |
57148ee7 | 6240 | |
3040bf3a AJ |
6241 | if ((at == pe_string || at == pe_long) && ft == pe_unknown) |
6242 | { | |
6243 | // propagate to formal type | |
6244 | ft = at; | |
6245 | resolved (ee->tok, ee->type, array->referent, i); | |
6246 | } | |
6247 | if (at == pe_stats) | |
6248 | invalid (ee->tok, at); | |
6249 | if (ft == pe_stats) | |
6250 | invalid (ee->tok, ft); | |
6251 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
6252 | mismatch (ee->tok, ee->type, array->referent, i); | |
6253 | if (at == pe_unknown) | |
6254 | unresolved (ee->tok); | |
6255 | } | |
6256 | for (unsigned i=0; i<e->array_slice.size(); i++) | |
45af9d1b | 6257 | if (e->array_slice[i]) |
3040bf3a AJ |
6258 | { |
6259 | expression* ee = e->array_slice[i]; | |
6260 | exp_type& ft = array->referent->index_types [i]; | |
6261 | t = ft; | |
6262 | ee->visit (this); | |
6263 | exp_type at = ee->type; | |
6264 | ||
6265 | if ((at == pe_string || at == pe_long) && ft == pe_unknown) | |
6266 | { | |
6267 | // propagate to formal type | |
6268 | ft = at; | |
6269 | resolved (ee->tok, ee->type, array->referent, i); | |
6270 | } | |
6271 | if (at == pe_stats) | |
6272 | invalid (ee->tok, at); | |
6273 | if (ft == pe_stats) | |
6274 | invalid (ee->tok, ft); | |
6275 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
6276 | mismatch (ee->tok, ee->type, array->referent, i); | |
6277 | if (at == pe_unknown) | |
6278 | unresolved (ee->tok); | |
6279 | } | |
6280 | } | |
c261711d JS |
6281 | t = pe_unknown; |
6282 | array->visit (this); | |
6283 | wanted_value = array->type; | |
6284 | } | |
6285 | ||
6286 | if (e->value) | |
6287 | { | |
6288 | if (wanted_value == pe_stats) | |
6289 | invalid(e->value->tok, wanted_value); | |
6290 | else if (wanted_value != pe_unknown) | |
6291 | check_arg_type(wanted_value, e->value); | |
6292 | else | |
6293 | { | |
6294 | t = pe_unknown; | |
6295 | e->value->visit (this); | |
6296 | } | |
69c68955 FCE |
6297 | } |
6298 | ||
fd5689dc FCE |
6299 | /* Prevent @sum etc. aggregate sorting on non-statistics arrays. */ |
6300 | if (wanted_value != pe_unknown) | |
6301 | if (e->sort_aggr != sc_none && wanted_value != pe_stats) | |
6302 | invalid (array->tok, wanted_value); | |
6303 | ||
27f21e8c DS |
6304 | if (e->limit) |
6305 | { | |
6306 | t = pe_long; | |
6307 | e->limit->visit (this); | |
6308 | } | |
6309 | ||
69c68955 | 6310 | t = pe_unknown; |
57148ee7 | 6311 | e->block->visit (this); |
69c68955 FCE |
6312 | } |
6313 | ||
6314 | ||
2b066ec1 | 6315 | void |
78f6bba6 | 6316 | typeresolution_info::visit_null_statement (null_statement*) |
2b066ec1 FCE |
6317 | { |
6318 | } | |
6319 | ||
6320 | ||
6321 | void | |
6322 | typeresolution_info::visit_expr_statement (expr_statement* e) | |
6323 | { | |
6324 | t = pe_unknown; | |
6325 | e->value->visit (this); | |
6326 | } | |
6327 | ||
6328 | ||
57148ee7 | 6329 | struct delete_statement_typeresolution_info: |
d98d459c GH |
6330 | public throwing_visitor |
6331 | { | |
6332 | typeresolution_info *parent; | |
6333 | delete_statement_typeresolution_info (typeresolution_info *p): | |
4af765b2 | 6334 | throwing_visitor (_("invalid operand of delete expression")), |
d98d459c GH |
6335 | parent (p) |
6336 | {} | |
6337 | ||
6338 | void visit_arrayindex (arrayindex* e) | |
6339 | { | |
6340 | parent->visit_arrayindex (e); | |
6341 | } | |
57148ee7 | 6342 | |
d98d459c GH |
6343 | void visit_symbol (symbol* e) |
6344 | { | |
6345 | exp_type ignored = pe_unknown; | |
57148ee7 | 6346 | assert (e->referent != 0); |
d98d459c GH |
6347 | resolve_2types (e, e->referent, parent, ignored); |
6348 | } | |
6349 | }; | |
6350 | ||
6351 | ||
2b066ec1 FCE |
6352 | void |
6353 | typeresolution_info::visit_delete_statement (delete_statement* e) | |
6354 | { | |
d98d459c GH |
6355 | delete_statement_typeresolution_info di (this); |
6356 | t = pe_unknown; | |
6357 | e->value->visit (&di); | |
2b066ec1 FCE |
6358 | } |
6359 | ||
6360 | ||
f3c26ea5 | 6361 | void |
78f6bba6 | 6362 | typeresolution_info::visit_next_statement (next_statement*) |
f3c26ea5 FCE |
6363 | { |
6364 | } | |
6365 | ||
6366 | ||
6367 | void | |
78f6bba6 | 6368 | typeresolution_info::visit_break_statement (break_statement*) |
f3c26ea5 FCE |
6369 | { |
6370 | } | |
6371 | ||
6372 | ||
6373 | void | |
78f6bba6 | 6374 | typeresolution_info::visit_continue_statement (continue_statement*) |
f3c26ea5 FCE |
6375 | { |
6376 | } | |
6377 | ||
6378 | ||
2b066ec1 FCE |
6379 | void |
6380 | typeresolution_info::visit_array_in (array_in* e) | |
6381 | { | |
ce10591c FCE |
6382 | // all unary operators only work on numerics |
6383 | exp_type t1 = t; | |
6384 | t = pe_unknown; // array value can be anything | |
6385 | e->operand->visit (this); | |
6386 | ||
6387 | if (t1 == pe_unknown && e->type != pe_unknown) | |
6388 | ; // already resolved | |
6389 | else if (t1 == pe_string || t1 == pe_stats) | |
6390 | mismatch (e->tok, t1, pe_long); | |
6391 | else if (e->type == pe_unknown) | |
6392 | { | |
6393 | e->type = pe_long; | |
6394 | resolved (e->tok, e->type); | |
6395 | } | |
2b066ec1 FCE |
6396 | } |
6397 | ||
6398 | ||
6399 | void | |
6400 | typeresolution_info::visit_return_statement (return_statement* e) | |
6401 | { | |
6402 | // This is like symbol, where the referent is | |
6403 | // the return value of the function. | |
6404 | ||
57148ee7 | 6405 | // translation pass will print error |
2b066ec1 | 6406 | if (current_function == 0) |
22f46231 | 6407 | return; |
2b066ec1 FCE |
6408 | |
6409 | exp_type& e_type = current_function->type; | |
6410 | t = current_function->type; | |
6411 | e->value->visit (this); | |
6412 | ||
6413 | if (e_type != pe_unknown && e->value->type != pe_unknown | |
6414 | && e_type != e->value->type) | |
18bac841 | 6415 | mismatch (e->value->tok, e->value->type, current_function); |
57148ee7 | 6416 | if (e_type == pe_unknown && |
2b066ec1 FCE |
6417 | (e->value->type == pe_long || e->value->type == pe_string)) |
6418 | { | |
6419 | // propagate non-statistics from value | |
6420 | e_type = e->value->type; | |
18bac841 | 6421 | resolved (e->value->tok, e_type, current_function); |
2b066ec1 FCE |
6422 | } |
6423 | if (e->value->type == pe_stats) | |
6424 | invalid (e->value->tok, e->value->type); | |
c3ed664e JS |
6425 | |
6426 | const exp_type_ptr& value_type = e->value->type_details; | |
6427 | if (value_type && current_function->type == e->value->type) | |
6428 | { | |
6429 | exp_type_ptr& func_type = current_function->type_details; | |
6430 | if (!func_type) | |
6431 | // The function can take on the type details of the return value. | |
6432 | resolved_details(value_type, func_type); | |
6433 | else if (*func_type != *value_type && *func_type != *null_type) | |
6434 | // Conflicting return types? NO TYPE FOR YOU! | |
6435 | resolved_details(null_type, func_type); | |
6436 | } | |
2b066ec1 FCE |
6437 | } |
6438 | ||
57148ee7 | 6439 | void |
d02548c0 GH |
6440 | typeresolution_info::visit_print_format (print_format* e) |
6441 | { | |
6442 | size_t unresolved_args = 0; | |
6443 | ||
1bbeef03 GH |
6444 | if (e->hist) |
6445 | { | |
6446 | e->hist->visit(this); | |
6447 | } | |
6448 | ||
6449 | else if (e->print_with_format) | |
d02548c0 GH |
6450 | { |
6451 | // If there's a format string, we can do both inference *and* | |
6452 | // checking. | |
6453 | ||
6454 | // First we extract the subsequence of formatting components | |
6455 | // which are conversions (not just literal string components) | |
6456 | ||
34201621 | 6457 | unsigned expected_num_args = 0; |
d02548c0 GH |
6458 | std::vector<print_format::format_component> components; |
6459 | for (size_t i = 0; i < e->components.size(); ++i) | |
6460 | { | |
6461 | if (e->components[i].type == print_format::conv_unspecified) | |
dc09353a | 6462 | throw SEMANTIC_ERROR (_("Unspecified conversion in print operator format string"), |
d02548c0 | 6463 | e->tok); |
b5852334 | 6464 | else if (e->components[i].type == print_format::conv_literal) |
d02548c0 GH |
6465 | continue; |
6466 | components.push_back(e->components[i]); | |
34201621 DB |
6467 | ++expected_num_args; |
6468 | if (e->components[i].widthtype == print_format::width_dynamic) | |
6469 | ++expected_num_args; | |
6470 | if (e->components[i].prectype == print_format::prec_dynamic) | |
6471 | ++expected_num_args; | |
d02548c0 GH |
6472 | } |
6473 | ||
6474 | // Then we check that the number of conversions and the number | |
6475 | // of args agree. | |
6476 | ||
34201621 | 6477 | if (expected_num_args != e->args.size()) |
dc09353a | 6478 | throw SEMANTIC_ERROR (_("Wrong number of args to formatted print operator"), |
d02548c0 GH |
6479 | e->tok); |
6480 | ||
6481 | // Then we check that the types of the conversions match the types | |
6482 | // of the args. | |
34201621 | 6483 | unsigned argno = 0; |
d02548c0 GH |
6484 | for (size_t i = 0; i < components.size(); ++i) |
6485 | { | |
34201621 DB |
6486 | // Check the dynamic width, if specified |
6487 | if (components[i].widthtype == print_format::width_dynamic) | |
6488 | { | |
6489 | check_arg_type (pe_long, e->args[argno]); | |
6490 | ++argno; | |
6491 | } | |
6492 | ||
6493 | // Check the dynamic precision, if specified | |
6494 | if (components[i].prectype == print_format::prec_dynamic) | |
6495 | { | |
6496 | check_arg_type (pe_long, e->args[argno]); | |
6497 | ++argno; | |
6498 | } | |
6499 | ||
d02548c0 GH |
6500 | exp_type wanted = pe_unknown; |
6501 | ||
6502 | switch (components[i].type) | |
6503 | { | |
d02548c0 GH |
6504 | case print_format::conv_unspecified: |
6505 | case print_format::conv_literal: | |
6506 | assert (false); | |
6507 | break; | |
6508 | ||
929eb962 JS |
6509 | case print_format::conv_pointer: |
6510 | case print_format::conv_number: | |
dc0b623a | 6511 | case print_format::conv_binary: |
fecccf83 | 6512 | case print_format::conv_char: |
ec03bd4b | 6513 | case print_format::conv_memory: |
30c94a80 | 6514 | case print_format::conv_memory_hex: |
d02548c0 GH |
6515 | wanted = pe_long; |
6516 | break; | |
6517 | ||
6518 | case print_format::conv_string: | |
6519 | wanted = pe_string; | |
6520 | break; | |
6521 | } | |
6522 | ||
6523 | assert (wanted != pe_unknown); | |
34201621 DB |
6524 | check_arg_type (wanted, e->args[argno]); |
6525 | ++argno; | |
d02548c0 GH |
6526 | } |
6527 | } | |
6528 | else | |
6529 | { | |
6530 | // Without a format string, the best we can do is require that | |
6531 | // each argument resolve to a concrete type. | |
6532 | for (size_t i = 0; i < e->args.size(); ++i) | |
6533 | { | |
6534 | t = pe_unknown; | |
6535 | e->args[i]->visit (this); | |
6536 | if (e->args[i]->type == pe_unknown) | |
6537 | { | |
6538 | unresolved (e->args[i]->tok); | |
6539 | ++unresolved_args; | |
6540 | } | |
6541 | } | |
6542 | } | |
57148ee7 | 6543 | |
d02548c0 GH |
6544 | if (unresolved_args == 0) |
6545 | { | |
6546 | if (e->type == pe_unknown) | |
6547 | { | |
6548 | if (e->print_to_stream) | |
6549 | e->type = pe_long; | |
6550 | else | |
57148ee7 | 6551 | e->type = pe_string; |
d02548c0 GH |
6552 | resolved (e->tok, e->type); |
6553 | } | |
6554 | } | |
6555 | else | |
6556 | { | |
6557 | e->type = pe_unknown; | |
6558 | unresolved (e->tok); | |
6559 | } | |
6560 | } | |
6561 | ||
6562 | ||
57148ee7 | 6563 | void |
d02548c0 GH |
6564 | typeresolution_info::visit_stat_op (stat_op* e) |
6565 | { | |
6566 | t = pe_stats; | |
6567 | e->stat->visit (this); | |
6568 | if (e->type == pe_unknown) | |
6569 | { | |
6570 | e->type = pe_long; | |
6571 | resolved (e->tok, e->type); | |
6572 | } | |
07c17d67 | 6573 | else if (e->type != pe_long) |
18bac841 | 6574 | mismatch (e->tok, pe_long, e->type); |
d02548c0 GH |
6575 | } |
6576 | ||
57148ee7 | 6577 | void |
d02548c0 GH |
6578 | typeresolution_info::visit_hist_op (hist_op* e) |
6579 | { | |
6580 | t = pe_stats; | |
6581 | e->stat->visit (this); | |
6582 | } | |
6583 | ||
2b066ec1 | 6584 | |
34201621 DB |
6585 | void |
6586 | typeresolution_info::check_arg_type (exp_type wanted, expression* arg) | |
6587 | { | |
6588 | t = wanted; | |
6589 | arg->visit (this); | |
6590 | ||
6591 | if (arg->type == pe_unknown) | |
6592 | { | |
6593 | arg->type = wanted; | |
18bac841 | 6594 | resolved (arg->tok, arg->type); |
34201621 DB |
6595 | } |
6596 | else if (arg->type != wanted) | |
6597 | { | |
18bac841 | 6598 | mismatch (arg->tok, wanted, arg->type); |
34201621 DB |
6599 | } |
6600 | } | |
6601 | ||
6602 | ||
5abd364d JS |
6603 | void |
6604 | typeresolution_info::check_local (vardecl* v) | |
6605 | { | |
6606 | if (v->arity != 0) | |
6607 | { | |
6608 | num_still_unresolved ++; | |
6609 | if (assert_resolvability) | |
6610 | session.print_error | |
dc09353a | 6611 | (SEMANTIC_ERROR (_("array locals not supported, missing global declaration? "), v->tok)); |
5abd364d JS |
6612 | } |
6613 | ||
6614 | if (v->type == pe_unknown) | |
6615 | unresolved (v->tok); | |
6616 | else if (v->type == pe_stats) | |
6617 | { | |
6618 | num_still_unresolved ++; | |
6619 | if (assert_resolvability) | |
6620 | session.print_error | |
dc09353a | 6621 | (SEMANTIC_ERROR (_("stat locals not supported, missing global declaration? "), v->tok)); |
5abd364d JS |
6622 | } |
6623 | else if (!(v->type == pe_long || v->type == pe_string)) | |
6624 | invalid (v->tok, v->type); | |
6625 | } | |
6626 | ||
6627 | ||
2b066ec1 FCE |
6628 | void |
6629 | typeresolution_info::unresolved (const token* tok) | |
6630 | { | |
6631 | num_still_unresolved ++; | |
6632 | ||
c74ddc54 | 6633 | if (assert_resolvability && mismatch_complexity <= 0) |
2b066ec1 | 6634 | { |
6c543717 | 6635 | stringstream msg; |
4af765b2 | 6636 | msg << _("unresolved type "); |
dc09353a | 6637 | session.print_error (SEMANTIC_ERROR (msg.str(), tok)); |
2b066ec1 FCE |
6638 | } |
6639 | } | |
6640 | ||
6641 | ||
6642 | void | |
6643 | typeresolution_info::invalid (const token* tok, exp_type pe) | |
6644 | { | |
6645 | num_still_unresolved ++; | |
6646 | ||
6647 | if (assert_resolvability) | |
6648 | { | |
6c543717 | 6649 | stringstream msg; |
022b623f | 6650 | if (tok && tok->type == tok_operator) |
4af765b2 | 6651 | msg << _("invalid operator"); |
2b066ec1 | 6652 | else |
4af765b2 | 6653 | msg << _("invalid type ") << pe; |
dc09353a | 6654 | session.print_error (SEMANTIC_ERROR (msg.str(), tok)); |
2b066ec1 FCE |
6655 | } |
6656 | } | |
6657 | ||
116562fc JL |
6658 | void |
6659 | typeresolution_info::mismatch (const binary_expression* e) | |
6660 | { | |
6661 | num_still_unresolved ++; | |
6662 | ||
c74ddc54 | 6663 | if (assert_resolvability && mismatch_complexity <= 1) |
116562fc JL |
6664 | { |
6665 | stringstream msg; | |
6666 | msg << _F("type mismatch: left and right sides don't agree (%s vs %s)", | |
6667 | lex_cast(e->left->type).c_str(), lex_cast(e->right->type).c_str()); | |
6668 | session.print_error (SEMANTIC_ERROR (msg.str(), e->tok)); | |
6669 | } | |
c74ddc54 JL |
6670 | else if (!assert_resolvability) |
6671 | mismatch_complexity = max(1, mismatch_complexity); | |
116562fc | 6672 | } |
2b066ec1 | 6673 | |
9e85f932 JL |
6674 | /* tok token where mismatch occurred |
6675 | * t1 type we expected (the 'good' type) | |
6676 | * t2 type we received (the 'bad' type) | |
6677 | * */ | |
2b066ec1 FCE |
6678 | void |
6679 | typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2) | |
6680 | { | |
6681 | num_still_unresolved ++; | |
6682 | ||
c74ddc54 | 6683 | if (assert_resolvability && mismatch_complexity <= 2) |
2b066ec1 | 6684 | { |
6c543717 | 6685 | stringstream msg; |
9e85f932 JL |
6686 | msg << _F("type mismatch: expected %s", lex_cast(t1).c_str()); |
6687 | if (t2 != pe_unknown) | |
6688 | msg << _F(" but found %s", lex_cast(t2).c_str()); | |
6689 | session.print_error (SEMANTIC_ERROR (msg.str(), tok)); | |
2b066ec1 | 6690 | } |
c74ddc54 JL |
6691 | else if (!assert_resolvability) |
6692 | mismatch_complexity = max(2, mismatch_complexity); | |
2b066ec1 FCE |
6693 | } |
6694 | ||
116562fc JL |
6695 | /* tok token where the mismatch happened |
6696 | * type type we received (the 'bad' type) | |
6697 | * decl declaration of mismatched symbol | |
6698 | * index if index-based (array index or function arg) | |
6699 | * */ | |
6700 | void | |
6701 | typeresolution_info::mismatch (const token *tok, exp_type type, | |
6702 | const symboldecl* decl, int index) | |
6703 | { | |
6704 | num_still_unresolved ++; | |
6705 | ||
c74ddc54 | 6706 | if (assert_resolvability && mismatch_complexity <= 3) |
116562fc | 6707 | { |
18bac841 JL |
6708 | assert(decl != NULL); |
6709 | ||
6710 | // If mismatch is against a function parameter from within the function | |
6711 | // itself (rather than a function call), then the index will be -1. We | |
6712 | // check here if the decl corresponds to one of the params and if so, | |
6713 | // adjust the index. | |
6714 | if (current_function != NULL && index == -1) | |
6715 | { | |
6716 | vector<vardecl*>& args = current_function->formal_args; | |
6717 | for (unsigned i = 0; i < args.size() && index < 0; i++) | |
6718 | if (args[i] == decl) | |
6719 | index = i; | |
6720 | } | |
6721 | ||
6722 | // get the declaration's original type and token | |
6723 | const resolved_type *original = NULL; | |
6724 | for (vector<resolved_type>::const_iterator it = resolved_types.begin(); | |
6725 | it != resolved_types.end() && original == NULL; ++it) | |
6726 | { | |
6727 | if (it->decl == decl && it->index == index) | |
6728 | original = &(*it); | |
6729 | } | |
6730 | ||
6731 | // print basic mismatch msg if we couldn't find the decl (this can happen | |
d2e3c0c7 JL |
6732 | // for explicitly typed decls e.g. myvar:long or for fabricated (already |
6733 | // resolved) decls e.g. __perf_read_*) | |
18bac841 JL |
6734 | if (original == NULL) |
6735 | { | |
6736 | session.print_error (SEMANTIC_ERROR ( | |
6737 | _F("type mismatch: expected %s but found %s", | |
6738 | lex_cast(type).c_str(), | |
6739 | lex_cast(decl->type).c_str()), | |
6740 | tok)); | |
6741 | return; | |
6742 | } | |
6743 | ||
6744 | // print where mismatch happened and chain with origin of decl type | |
6745 | // resolution | |
6746 | stringstream msg; | |
6747 | ||
6748 | if (index >= 0) | |
6749 | msg << _F("index %d ", index); | |
6750 | msg << _F("type mismatch (%s)", lex_cast(type).c_str()); | |
6751 | semantic_error err(ERR_SRC, msg.str(), tok); | |
6752 | ||
6753 | stringstream chain_msg; | |
6754 | chain_msg << _("type"); | |
6755 | if (index >= 0) | |
40136471 | 6756 | chain_msg << _F(" of index %d", index); |
18bac841 JL |
6757 | chain_msg << _F(" was first inferred here (%s)", |
6758 | lex_cast(decl->type).c_str()); | |
c081af73 | 6759 | semantic_error chain(ERR_SRC, chain_msg.str(), original->tok); |
18bac841 | 6760 | |
c081af73 | 6761 | err.set_chain(chain); |
18bac841 | 6762 | session.print_error (err); |
116562fc | 6763 | } |
c74ddc54 JL |
6764 | else if (!assert_resolvability) |
6765 | mismatch_complexity = max(3, mismatch_complexity); | |
116562fc JL |
6766 | } |
6767 | ||
2b066ec1 | 6768 | |
116562fc JL |
6769 | /* tok token where resolution occurred |
6770 | * type type to which we resolved | |
6771 | * decl declaration of resolved symbol | |
6772 | * index if index-based (array index or function arg) | |
6773 | * */ | |
2b066ec1 | 6774 | void |
dabd71bb | 6775 | typeresolution_info::resolved (const token *tok, exp_type, |
116562fc | 6776 | const symboldecl* decl, int index) |
2b066ec1 FCE |
6777 | { |
6778 | num_newly_resolved ++; | |
18bac841 JL |
6779 | |
6780 | // We only use the resolved_types vector to give better mismatch messages | |
6781 | // involving symbols. So don't bother adding it if we're not given a decl | |
6782 | if (decl != NULL) | |
6783 | { | |
6784 | // As a fail-safe, if the decl & index is already in the vector, then | |
6785 | // modify it instead of adding another one to ensure uniqueness. This | |
6786 | // should never happen since we only call resolved once for each decl & | |
6787 | // index, but better safe than sorry. (IE. if it does happen, better have | |
6788 | // the latest resolution info for better mismatch reporting later). | |
6789 | for (unsigned i = 0; i < resolved_types.size(); i++) | |
6790 | { | |
6791 | if (resolved_types[i].decl == decl | |
6792 | && resolved_types[i].index == index) | |
6793 | { | |
6794 | resolved_types[i].tok = tok; | |
6795 | return; | |
6796 | } | |
6797 | } | |
6798 | resolved_type res(tok, decl, index); | |
6799 | resolved_types.push_back(res); | |
6800 | } | |
2b066ec1 FCE |
6801 | } |
6802 | ||
eb79eb0a JS |
6803 | void |
6804 | typeresolution_info::resolved_details (const exp_type_ptr& src, | |
6805 | exp_type_ptr& dest) | |
6806 | { | |
6807 | num_newly_resolved ++; | |
6808 | dest = src; | |
6809 | } | |
6810 | ||
73267b89 | 6811 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |