summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog28
-rw-r--r--elaborate.cxx24
-rw-r--r--parse.cxx28
-rw-r--r--staptree.cxx7
-rwxr-xr-xtestsuite/buildok/print_histogram_entry.stp29
-rw-r--r--translate.cxx203
6 files changed, 264 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index bbbead3d..7bcc50b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2005-12-02 Graydon Hoare <graydon@redhat.com>
+
+ * elaborate.cxx (mutated_var_collector): Forward
+ traversal portion of calls to base class.
+ (mutated_var_collector::visit_arrayindex): Resolve
+ arrayindex-into-histogram expression as pe_long.
+ (typeresolution_info::visit_print_format): Traverse
+ into histogram if present.
+
+ * parse.cxx (parse_symbol): Handle parse ambiguity surrounding
+ print(@hist_op(...)[...]).
+
+ * staptree.cxx (traversing_visitor::visit_arrayindex): Visit
+ base member of arrayindex.
+
+ * translate.cxx (c_unparser::histogram_index_check): New method.
+ (var::hist): Fix bug.
+ (var::buckets): New method.
+ (stmt_expr::stmt_expr): Print with newline.
+ (c_unparser::load_map_indices): Handle indexing-histogram case.
+ (c_tmpcounter::visit_arrayindex): Likewise.
+ (c_unparser::visit_arrayindex): Likewise.
+ (c_tmpcounter_assignment::visit_arrayindex): Throw error when
+ user attempts to write to histogram bucket.
+ (c_unparser_assignment::visit_arrayindex): Likewise.
+
+ * testsuite/buildok/print_histogram_entry.stp: New test.
+
2005-12-02 Frank Ch. Eigler <fche@elastic.org>
* configure.ac: Bump version number.
diff --git a/elaborate.cxx b/elaborate.cxx
index ac4bd0f6..7f8a0b91 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -520,8 +520,7 @@ struct mutated_var_collector
if (vd)
mutated_vars->insert (vd);
}
- e->left->visit (this);
- e->right->visit (this);
+ traversing_visitor::visit_assignment(e);
}
void visit_arrayindex (arrayindex *e)
@@ -534,6 +533,7 @@ struct mutated_var_collector
else
throw semantic_error("Assignment to read-only histogram bucket", e->tok);
}
+ traversing_visitor::visit_arrayindex (e);
}
};
@@ -570,6 +570,7 @@ struct no_var_mutation_during_iteration_check
}
}
}
+ traversing_visitor::visit_arrayindex (e);
}
void visit_functioncall (functioncall* e)
@@ -591,8 +592,7 @@ struct no_var_mutation_during_iteration_check
}
}
- for (unsigned i=0; i<e->args.size(); i++)
- e->args[i]->visit (this);
+ traversing_visitor::visit_functioncall (e);
}
void visit_foreach_loop(foreach_loop* s)
@@ -602,9 +602,7 @@ struct no_var_mutation_during_iteration_check
if (vd)
vars_being_iterated.push_back (vd);
- for (unsigned i=0; i<s->indexes.size(); i++)
- s->indexes[i]->visit (this);
- s->block->visit (this);
+ traversing_visitor::visit_foreach_loop (s);
if (vd)
vars_being_iterated.pop_back();
@@ -1594,6 +1592,11 @@ typeresolution_info::visit_arrayindex (arrayindex* e)
if (e->indexes[0]->type != pe_long)
unresolved (e->tok);
hist->visit (this);
+ if (e->type != pe_long)
+ {
+ e->type = pe_long;
+ resolved (e->tok, pe_long);
+ }
return;
}
@@ -1914,7 +1917,12 @@ typeresolution_info::visit_print_format (print_format* e)
{
size_t unresolved_args = 0;
- if (e->print_with_format)
+ if (e->hist)
+ {
+ e->hist->visit(this);
+ }
+
+ else if (e->print_with_format)
{
// If there's a format string, we can do both inference *and*
// checking.
diff --git a/parse.cxx b/parse.cxx
index fe10c75c..e46d3973 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -1997,9 +1997,31 @@ parser::parse_symbol ()
// construct. This is sort of gross but it avoids
// promoting histogram references to typeful
// expressions.
- fmt->hist = NULL;
- t = parse_hist_op_or_bare_name(fmt->hist, name);
- assert(fmt->hist);
+
+ hop = NULL;
+ t = parse_hist_op_or_bare_name(hop, name);
+ assert(hop);
+
+ // It is, sadly, possible that even while parsing a
+ // hist_op, we *mis-guessed* and the user wishes to
+ // print(@hist_op(foo)[bucket]), a scalar. In that case
+ // we must parse the arrayindex and print an expression.
+
+ if (!peek_op ("["))
+ fmt->hist = hop;
+ else
+ {
+ // This is simplified version of the
+ // multi-array-index parser below, because we can
+ // only ever have one index on a histogram anyways.
+ expect_op("[");
+ struct arrayindex* ai = new arrayindex;
+ ai->tok = t;
+ ai->base = hop;
+ ai->indexes.push_back (parse_expression ());
+ expect_op("]");
+ fmt->args.push_back(ai);
+ }
}
else
{
diff --git a/staptree.cxx b/staptree.cxx
index 3015c796..2ad2d906 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -1375,6 +1375,13 @@ traversing_visitor::visit_target_symbol (target_symbol* e)
void
traversing_visitor::visit_arrayindex (arrayindex* e)
{
+ symbol *array = NULL;
+ hist_op *hist = NULL;
+ classify_indexable(e->base, array, hist);
+ if (array)
+ return array->visit(this);
+ else
+ return hist->visit(this);
for (unsigned i=0; i<e->indexes.size(); i++)
e->indexes[i]->visit (this);
}
diff --git a/testsuite/buildok/print_histogram_entry.stp b/testsuite/buildok/print_histogram_entry.stp
new file mode 100755
index 00000000..bf87ecbe
--- /dev/null
+++ b/testsuite/buildok/print_histogram_entry.stp
@@ -0,0 +1,29 @@
+#! stap -p4
+
+global foo
+global i
+
+probe begin
+{
+ print("starting up\n")
+ i = 0
+}
+
+probe timer.jiffies(100)
+{
+ printf("ping %d\n", i)
+ foo <<< i
+ if (i++ > 15)
+ exit()
+}
+
+probe end
+{
+ print("shutting down\n")
+ printf("count %d, avg %d\n", @count(foo), @avg(foo))
+ for (i = 0; i < 7; ++i)
+ {
+ printf("bucket %d: %d\n", i, @hist_log(foo)[i])
+ }
+}
+
diff --git a/translate.cxx b/translate.cxx
index 1f87f70c..45bd6696 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -117,6 +117,7 @@ struct c_unparser: public unparser, public visitor
vector<tmpvar> & idx);
void load_aggregate (expression *e, aggvar & agg);
+ string histogram_index_check(var & vase, tmpvar & idx) const;
void collect_map_index_types(vector<vardecl* > const & vars,
set< pair<vector<exp_type>, exp_type> > & types);
@@ -341,7 +342,15 @@ public:
string hist() const
{
assert (ty == pe_stats);
- return "&(" + qname() + "->hist)";
+ assert (sd.type != statistic_decl::none);
+ return "(&(" + qname() + "->hist))";
+ }
+
+ string buckets() const
+ {
+ assert (ty == pe_stats);
+ assert (sd.type != statistic_decl::none);
+ return "(" + qname() + "->hist.buckets)";
}
string init() const
@@ -397,7 +406,7 @@ struct stmt_expr
c_unparser & c;
stmt_expr(c_unparser & c) : c(c)
{
- c.o->line() << "({";
+ c.o->newline() << "({";
c.o->indent(1);
}
~stmt_expr()
@@ -2494,37 +2503,6 @@ c_unparser::visit_target_symbol (target_symbol* e)
void
-c_tmpcounter::visit_arrayindex (arrayindex *e)
-{
- symbol *array;
- hist_op *hist;
- classify_indexable (e->base, array, hist);
-
- if (array)
- {
- vardecl* r = array->referent;
-
- // One temporary per index dimension.
- for (unsigned i=0; i<r->index_types.size(); i++)
- {
- tmpvar ix = parent->gensym (r->index_types[i]);
- ix.declare (*parent);
- e->indexes[i]->visit(this);
- }
-
- // The index-expression result.
- tmpvar res = parent->gensym (e->type);
- res.declare (*parent);
- }
- else
- {
- // FIXME: fill in some logic here!
- assert(false);
- }
-}
-
-
-void
c_unparser::load_map_indices(arrayindex *e,
vector<tmpvar> & idx)
{
@@ -2556,8 +2534,13 @@ c_unparser::load_map_indices(arrayindex *e,
}
else
{
- // FIXME: fill in some logic here!
- assert(false);
+ assert (e->indexes.size() == 1);
+ assert (e->indexes[0]->type == pe_long);
+ tmpvar ix = gensym (pe_long);
+ o->newline() << "c->last_stmt = "
+ << lex_cast_qstring(*e->indexes[0]->tok) << ";";
+ c_assign (ix.qname(), e->indexes[0], "array index copy");
+ idx.push_back(ix);
}
}
@@ -2623,8 +2606,17 @@ c_unparser::load_aggregate (expression *e, aggvar & agg)
}
}
+
+string
+c_unparser::histogram_index_check(var & base, tmpvar & idx) const
+{
+ return "((" + idx.qname() + " >= 0)"
+ + " && (" + idx.qname() + " < " + base.buckets() + "))";
+}
+
+
void
-c_unparser::visit_arrayindex (arrayindex* e)
+c_tmpcounter::visit_arrayindex (arrayindex *e)
{
symbol *array;
hist_op *hist;
@@ -2632,17 +2624,105 @@ c_unparser::visit_arrayindex (arrayindex* e)
if (array)
{
+ vardecl* r = array->referent;
+
+ // One temporary per index dimension.
+ for (unsigned i=0; i<r->index_types.size(); i++)
+ {
+ tmpvar ix = parent->gensym (r->index_types[i]);
+ ix.declare (*parent);
+ e->indexes[i]->visit(this);
+ }
+
+ // The index-expression result.
+ tmpvar res = parent->gensym (e->type);
+ res.declare (*parent);
+ }
+ else
+ {
+
+ assert(hist);
+
+ // Note: this is a slightly tricker-than-it-looks allocation of
+ // temporaries. The reason is that we're in the branch handling
+ // histogram-indexing, and the histogram might be build over an
+ // indexable entity itself. For example if we have:
+ //
+ // global foo
+ // ...
+ // foo[getpid(), geteuid()] <<< 1
+ // ...
+ // print @log_hist(foo[pid, euid])[bucket]
+ //
+ // We are looking at the @log_hist(...)[bucket] expression, so
+ // allocating one tmpvar for calculating bucket (the "index" of
+ // this arrayindex expression), and one tmpvar for storing the
+ // result in, just as normal.
+ //
+ // But we are *also* going to call load_aggregate on foo, which
+ // will itself require tmpvars for each of its indices. Since
+ // this is not handled by delving into the subexpression (it
+ // would be if hist were first-class in the type system, but
+ // it's not) we we allocate all the tmpvars used in such a
+ // subexpression up here: first our own aggvar, then our index
+ // (bucket) tmpvar, then all the index tmpvars of our
+ // pe_stat-valued subexpression, then our result.
+
+ // First all the stuff related to indexing into the histogram
+
+ if (e->indexes.size() != 1)
+ throw semantic_error("Invalid indexing of histogram", e->tok);
+ tmpvar ix = parent->gensym (pe_long);
+ ix.declare (*parent);
+ e->indexes[0]->visit(this);
+ tmpvar res = parent->gensym (pe_long);
+ res.declare (*parent);
+
+ // Then the aggregate, and all the tmpvars needed by our call to
+ // load_aggregate().
+
+ aggvar agg = parent->gensym_aggregate ();
+ agg.declare(*(this->parent));
+
+ symbol *sym = get_symbol_within_expression (hist->stat);
+ var v = parent->getvar(sym->referent, sym->tok);
+ if (sym->referent->arity != 0)
+ {
+ arrayindex *arr = NULL;
+ if (!expression_is_arrayindex (hist->stat, arr))
+ throw semantic_error("expected arrayindex expression in printed hist_op", e->tok);
+
+ for (unsigned i=0; i<sym->referent->index_types.size(); i++)
+ {
+ tmpvar ix = parent->gensym (sym->referent->index_types[i]);
+ ix.declare (*parent);
+ arr->indexes[i]->visit(this);
+ }
+ }
+ }
+}
+
+
+void
+c_unparser::visit_arrayindex (arrayindex* e)
+{
+ symbol *array;
+ hist_op *hist;
+ classify_indexable (e->base, array, hist);
+
+ if (array)
+ {
// Visiting an statistic-valued array in a non-lvalue context is prohibited.
if (array->referent->type == pe_stats)
throw semantic_error ("statistic-valued array in rvalue context", e->tok);
stmt_expr block(*this);
-
+
// NB: Do not adjust the order of the next few lines; the tmpvar
// allocation order must remain the same between
// c_unparser::visit_arrayindex and c_tmpcounter::visit_arrayindex
-
+
vector<tmpvar> idx;
load_map_indices (e, idx);
tmpvar res = gensym (e->type);
@@ -2670,8 +2750,45 @@ c_unparser::visit_arrayindex (arrayindex* e)
}
else
{
- // FIXME: fill in some logic here!
- assert(false);
+ // See commentary in c_tmpcounter::visit_arrayindex
+
+ assert(hist);
+ stmt_expr block(*this);
+
+ // NB: Do not adjust the order of the next few lines; the tmpvar
+ // allocation order must remain the same between
+ // c_unparser::visit_arrayindex and c_tmpcounter::visit_arrayindex
+
+ vector<tmpvar> idx;
+ load_map_indices (e, idx);
+ tmpvar res = gensym (e->type);
+
+ aggvar agg = gensym_aggregate ();
+ load_aggregate(hist->stat, agg);
+
+ // These should have faulted during elaboration if not true.
+ assert(idx.size() == 1);
+ assert(idx[0].type() == pe_long);
+
+ symbol *sym = get_symbol_within_expression (hist->stat);
+ var v = getvar(sym->referent, sym->tok);
+ v.assert_hist_compatible(*hist);
+
+ {
+ varlock_w guard(*this, v);
+ o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
+ o->newline() << "if (" << histogram_index_check(v, idx[0]) << ")";
+ o->newline() << "{";
+ o->newline(1) << res << " = " << agg << "->histogram[" << idx[0] << "];";
+ o->newline(-1) << "}";
+ o->newline() << "else";
+ o->newline() << "{";
+ o->newline(1) << "c->last_error = \"Histogram index out of range\";";
+ o->newline() << res << " = 0;";
+ o->newline(-1) << "}";
+ }
+
+ o->newline() << res << ";";
}
}
@@ -2712,8 +2829,7 @@ c_tmpcounter_assignment::visit_arrayindex (arrayindex *e)
}
else
{
- // FIXME: fill in some logic here!
- assert(false);
+ throw semantic_error("cannot assign to histogram buckets", e->tok);
}
}
@@ -2804,8 +2920,7 @@ c_unparser_assignment::visit_arrayindex (arrayindex *e)
}
else
{
- // FIXME: fill in some logic here!
- assert(false);
+ throw semantic_error("cannot assign to histogram buckets", e->tok);
}
}