summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog52
-rw-r--r--elaborate.cxx27
-rw-r--r--elaborate.h1
-rw-r--r--parse.cxx57
-rw-r--r--parse.h4
-rw-r--r--staptree.h18
-rwxr-xr-xtestsuite/semko/thirty.stp11
-rwxr-xr-xtestsuite/semko/thirtyone.stp11
-rwxr-xr-xtestsuite/semko/twentyeight.stp12
-rwxr-xr-xtestsuite/semko/twentyfive.stp12
-rwxr-xr-xtestsuite/semko/twentyfour.stp12
-rwxr-xr-xtestsuite/semko/twentynine.stp11
-rwxr-xr-xtestsuite/semko/twentyseven.stp17
-rwxr-xr-xtestsuite/semko/twentysix.stp12
-rw-r--r--translate.cxx232
15 files changed, 439 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index cbd613fb..f3b38c22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2005-10-20 Graydon Hoare <graydon@redhat.com>
+
+ PR 917 (incomplete)
+ * staptree.h (struct statistic_decl): New struct.
+ (stapfile::stat_decls): New member.
+
+ * parse.h, parse.cxx
+ (parser::expect_known): Fix typo.
+ (parser::expect_number): New method.
+ (parser::parse_global): Parse global statistic_decls.
+
+ * elaborate.h (systemtap_session::stat_decls): New member.
+ * elaborate.cxx (semantic_pass_symbols): Copy per-file stat_decls
+ to session-wide.
+ (typeresolution_info::visit_assignment): Detect some semantic stats
+ errors in type resolution pass.
+
+ * translate.cxx (var::sd): New private member.
+ (var::var): Initialize it.
+ (var::sdecl): New accessor.
+ (var::init): Handle stats values.
+ (mapvar::mapvar): Pass through statistic_decl to var ctor.
+ (mapvar::get): Test for long explicitly.
+ (mapvar::set): Likewise.
+ (mapvar::init): Handle stats values.
+ (c_unparser::emit_common_header): Remove typedef of stats_t,
+ include stat.c when necessary.
+ (mapvar::key_typename): Typo.
+ (c_unparser::emit_map_type_instantiations): Thinko: value_typename not key_typename.
+ (c_unparser::c_typename): Implementation typename is "Stat", not "stats_t".
+ (c_unparser::c_assign): Fix bad error message.
+ (c_unparser_assignment::c_assignop): Handle operator <<<.
+ (c_unparser::getvar): Feed session statistic_decl into var.
+ (c_unparser::getmap): Likewise.
+ (c_unparser::visit_assignment): Handle operator <<<.
+ (c_tmpcounter_assignment::visit_symbol): Derive type from rvalue when present.
+ (c_unparser_assignment::visit_symbol)
+ (c_tmpcounter_assignment::visit_arrayindex)
+ (c_unparser_assignment::load_map_indices): Likewise.
+ (c_unparser::visit_arrayindex): Likewise, and Prohibit statistic rvalues.
+ (c_unparser_assignment::visit_arrayindex): Handle operator <<<.
+
+ * testsuite/semko/twentyfour.stp:
+ * testsuite/semko/twentyfive.stp:
+ * testsuite/semko/twentysix.stp:
+ * testsuite/semko/twentyseven.stp:
+ * testsuite/semko/twentyeight.stp:
+ * testsuite/semko/twentynine.stp:
+ * testsuite/semko/thirty.stp:
+ * testsuite/semko/thirtyone.stp: New tests for prohibited statistic contexts.
+ * testsuite/buildok/twentytwo.stp: New test for legal statistic contexts.
+
2005-10-19 Tom Zanussi <zanussi@us.ibm.com>
PR 1194.
diff --git a/elaborate.cxx b/elaborate.cxx
index 06f6d01c..890e9dc0 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -608,6 +608,23 @@ semantic_pass_symbols (systemtap_session& s)
for (unsigned i=0; i<dome->embeds.size(); i++)
s.embeds.push_back (dome->embeds[i]);
+ for (std::map<std::string, statistic_decl>::const_iterator i =
+ dome->stat_decls.begin(); i != dome->stat_decls.end(); ++i)
+ {
+ try
+ {
+
+ if (s.stat_decls.find(i->first) != s.stat_decls.end())
+ throw semantic_error("multiple statistic declarations for " + i->first);
+ s.stat_decls.insert(std::make_pair(i->first,
+ i->second));
+ }
+ catch (const semantic_error& e)
+ {
+ s.print_error (e);
+ }
+ }
+
// Pass 2: process functions
for (unsigned i=0; i<dome->functions.size(); i++)
@@ -1130,12 +1147,20 @@ typeresolution_info::visit_assignment (assignment *e)
e->left->visit (this);
t = pe_long;
e->right->visit (this);
- if (e->type == pe_unknown)
+ if (e->type == pe_unknown ||
+ e->type == pe_stats)
{
e->type = pe_long;
resolved (e->tok, e->type);
}
}
+
+ else if (e->left->type == pe_stats)
+ invalid (e->left->tok, e->left->type);
+
+ else if (e->right->type == pe_stats)
+ invalid (e->right->tok, e->right->type);
+
else if (e->op == "+=" || // numeric only
e->op == "-=" ||
e->op == "*=" ||
diff --git a/elaborate.h b/elaborate.h
index a4546274..0abc04e0 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -235,6 +235,7 @@ struct systemtap_session
std::vector<functiondecl*> functions;
std::vector<derived_probe*> probes;
std::vector<embeddedcode*> embeds;
+ std::map<std::string, statistic_decl> stat_decls;
// module-referencing file handles
std::map<std::string,int> module_fds;
diff --git a/parse.cxx b/parse.cxx
index dc9024c9..2bcf9231 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -15,6 +15,7 @@
#include <cstdlib>
#include <cerrno>
#include <climits>
+#include <sstream>
using namespace std;
@@ -160,7 +161,7 @@ const token*
parser::expect_known (token_type tt, string const & expected)
{
const token *t = next();
- if (! t && t->type == tt && t->content == expected)
+ if (! (t && t->type == tt && t->content == expected))
throw parse_error ("expected '" + expected + "'");
return t;
}
@@ -190,6 +191,16 @@ parser::expect_kw (std::string const & expected)
return expect_known (tok_identifier, expected);
}
+const token*
+parser::expect_number (int64_t & expected)
+{
+ std::string tmp;
+ token const * tt = expect_unknown (tok_number, tmp);
+ istringstream iss(tmp);
+ iss >> expected;
+ return tt;
+}
+
const token*
parser::expect_ident (std::string & target)
@@ -507,7 +518,7 @@ parser::parse ()
if (t->type == tok_identifier && t->content == "probe")
parse_probe (f->probes, f->aliases);
else if (t->type == tok_identifier && t->content == "global")
- parse_global (f->globals);
+ parse_global (f->globals, f->stat_decls);
else if (t->type == tok_identifier && t->content == "function")
parse_functiondecl (f->functions);
else if (t->type == tok_embedded)
@@ -713,7 +724,8 @@ parser::parse_statement ()
void
-parser::parse_global (vector <vardecl*>& globals)
+parser::parse_global (vector <vardecl*>& globals,
+ std::map<std::string, statistic_decl> &stat_decls)
{
const token* t0 = next ();
if (! (t0->type == tok_identifier && t0->content == "global"))
@@ -725,15 +737,48 @@ parser::parse_global (vector <vardecl*>& globals)
if (! (t->type == tok_identifier))
throw parse_error ("expected identifier");
+ statistic_decl sd;
+
+ if (t->content == "log_hist")
+ {
+ std::string tmp;
+ expect_op ("(");
+ t = expect_ident (tmp);
+ expect_op (",");
+ expect_number (sd.logarithmic_buckets);
+ expect_op (")");
+ sd.type = statistic_decl::logarithmic;
+ }
+ else if (t->content == "linear_hist")
+ {
+ std::string tmp;
+ expect_op ("(");
+ t = expect_ident (tmp);
+ expect_op (",");
+ expect_number (sd.linear_low);
+ expect_op (",");
+ expect_number (sd.linear_high);
+ expect_op (",");
+ expect_number (sd.linear_step);
+ expect_op (")");
+ sd.type = statistic_decl::linear;
+ }
+
for (unsigned i=0; i<globals.size(); i++)
if (globals[i]->name == t->content)
- throw parse_error ("duplicate global name");
-
+ throw parse_error ("duplicate global name");
+
vardecl* d = new vardecl;
d->name = t->content;
d->tok = t;
globals.push_back (d);
+ if (sd.type != statistic_decl::none)
+ {
+ d->type = pe_stats;
+ stat_decls[d->name] = sd;
+ }
+
t = peek ();
if (t && t->type == tok_operator && t->content == ",")
{
@@ -1701,7 +1746,7 @@ parser::parse_symbol ()
{
next();
expect_unknown (tok_number, c);
- expect_op ("]");
+ expect_op ("]");
tsym->components.push_back
(make_pair (target_symbol::comp_literal_array_index, c));
}
diff --git a/parse.h b/parse.h
index 316f8258..f8ef1ac2 100644
--- a/parse.h
+++ b/parse.h
@@ -100,6 +100,7 @@ private:
// convenience forms
const token* expect_op (std::string const & expected);
const token* expect_kw (std::string const & expected);
+ const token* expect_number (int64_t & expected);
const token* expect_ident (std::string & target);
bool peek_op (std::string const & op);
bool peek_kw (std::string const & kw);
@@ -109,7 +110,8 @@ private:
private: // nonterminals
void parse_probe (std::vector<probe*>&, std::vector<probe_alias*>&);
- void parse_global (std::vector<vardecl*>&);
+ void parse_global (std::vector<vardecl*>&,
+ std::map<std::string, statistic_decl> &stat_decls);
void parse_functiondecl (std::vector<functiondecl*>&);
embeddedcode* parse_embeddedcode ();
probe_point* parse_probe_point ();
diff --git a/staptree.h b/staptree.h
index 8bc901d5..072cc2e2 100644
--- a/staptree.h
+++ b/staptree.h
@@ -9,6 +9,7 @@
#ifndef STAPTREE_H
#define STAPTREE_H
+#include <map>
#include <stack>
#include <string>
#include <vector>
@@ -35,7 +36,23 @@ struct semantic_error: public std::runtime_error
runtime_error (msg), tok1 (t1), msg2 (m2), tok2 (t2) {}
};
+// ------------------------------------------------------------------------
+struct statistic_decl
+{
+ statistic_decl()
+ : type(none),
+ logarithmic_buckets(0),
+ linear_low(0), linear_high(0), linear_step(0)
+ {}
+ enum { none, linear, logarithmic } type;
+ int64_t logarithmic_buckets;
+ int64_t linear_low;
+ int64_t linear_high;
+ int64_t linear_step;
+};
+
+// ------------------------------------------------------------------------
enum exp_type
{
@@ -392,6 +409,7 @@ struct stapfile
std::vector<functiondecl*> functions;
std::vector<vardecl*> globals;
std::vector<embeddedcode*> embeds;
+ std::map<std::string, statistic_decl> stat_decls;
bool privileged;
stapfile (): privileged (false) {}
void print (std::ostream& o) const;
diff --git a/testsuite/semko/thirty.stp b/testsuite/semko/thirty.stp
new file mode 100755
index 00000000..b8f0ab4b
--- /dev/null
+++ b/testsuite/semko/thirty.stp
@@ -0,0 +1,11 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10)
+
+probe end
+{
+ x = 10
+}
+
diff --git a/testsuite/semko/thirtyone.stp b/testsuite/semko/thirtyone.stp
new file mode 100755
index 00000000..4b6e98d5
--- /dev/null
+++ b/testsuite/semko/thirtyone.stp
@@ -0,0 +1,11 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10)
+
+probe end
+{
+ x[10] = 10
+}
+
diff --git a/testsuite/semko/twentyeight.stp b/testsuite/semko/twentyeight.stp
new file mode 100755
index 00000000..68590f86
--- /dev/null
+++ b/testsuite/semko/twentyeight.stp
@@ -0,0 +1,12 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10)
+
+probe end
+{
+ x <<< 10
+ x++
+}
+
diff --git a/testsuite/semko/twentyfive.stp b/testsuite/semko/twentyfive.stp
new file mode 100755
index 00000000..7ac7e099
--- /dev/null
+++ b/testsuite/semko/twentyfive.stp
@@ -0,0 +1,12 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10), log_hist(y, 10)
+
+
+probe end
+{
+ x = y[10]
+}
+
diff --git a/testsuite/semko/twentyfour.stp b/testsuite/semko/twentyfour.stp
new file mode 100755
index 00000000..81a69902
--- /dev/null
+++ b/testsuite/semko/twentyfour.stp
@@ -0,0 +1,12 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10), log_hist(y, 10)
+
+
+probe end
+{
+ y = x
+}
+
diff --git a/testsuite/semko/twentynine.stp b/testsuite/semko/twentynine.stp
new file mode 100755
index 00000000..8cc2e2d5
--- /dev/null
+++ b/testsuite/semko/twentynine.stp
@@ -0,0 +1,11 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10)
+
+probe end
+{
+ x <<< 10 <<< 11
+}
+
diff --git a/testsuite/semko/twentyseven.stp b/testsuite/semko/twentyseven.stp
new file mode 100755
index 00000000..a678bcd2
--- /dev/null
+++ b/testsuite/semko/twentyseven.stp
@@ -0,0 +1,17 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10)
+
+function foo(bar)
+{
+ bar <<< x
+}
+
+probe end
+{
+ x <<< 10
+ foo(x)
+}
+
diff --git a/testsuite/semko/twentysix.stp b/testsuite/semko/twentysix.stp
new file mode 100755
index 00000000..34d6d1d3
--- /dev/null
+++ b/testsuite/semko/twentysix.stp
@@ -0,0 +1,12 @@
+#! stap -p2
+
+# need one of these for each prohibited statistic operation
+
+global log_hist(x, 10)
+
+
+probe end
+{
+ x[10] = 10
+}
+
diff --git a/translate.cxx b/translate.cxx
index 1d7ed7ac..7a37c3a1 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -233,10 +233,15 @@ class var
{
bool local;
exp_type ty;
+ statistic_decl sd;
string name;
public:
+ var(bool local, exp_type ty, statistic_decl const & sd, string const & name)
+ : local(local), ty(ty), sd(sd), name(name)
+ {}
+
var(bool local, exp_type ty, string const & name)
: local(local), ty(ty), name(name)
{}
@@ -246,6 +251,11 @@ public:
return local;
}
+ statistic_decl const & sdecl() const
+ {
+ return sd;
+ }
+
exp_type type() const
{
return ty;
@@ -267,6 +277,29 @@ public:
return qname() + "[0] = '\\0';";
case pe_long:
return qname() + " = 0;";
+ case pe_stats:
+ switch (sd.type)
+ {
+ case statistic_decl::none:
+ assert(false);
+ break;
+
+ case statistic_decl::linear:
+ return (qname()
+ + " = _stp_stat_init (HIST_LINEAR"
+ + ", " + stringify(sd.linear_low)
+ + ", " + stringify(sd.linear_high)
+ + ", " + stringify(sd.linear_step)
+ + ");");
+ break;
+
+ case statistic_decl::logarithmic:
+ return (qname()
+ + " = _stp_stat_init (HIST_LOG"
+ + ", " + stringify(sd.logarithmic_buckets)
+ + ");");
+ break;
+ }
default:
throw semantic_error("unsupported initializer for " + qname());
}
@@ -374,9 +407,10 @@ struct mapvar
{
vector<exp_type> index_types;
mapvar (bool local, exp_type ty,
+ statistic_decl const & sd,
string const & name,
vector<exp_type> const & index_types)
- : var (local, ty, name),
+ : var (local, ty, sd, name),
index_types (index_types)
{}
@@ -417,8 +451,10 @@ struct mapvar
return "({ char *v = "
"_stp_map_get_" + shortname(type()) + " (" + qname() + "); "
"if (!v) v = \"\"; v; })";
- else // long?
+ else if (type() == pe_long)
return "_stp_map_get_" + shortname(type()) + " (" + qname() + ")";
+ else
+ throw semantic_error("getting a value from an unsupported map type");
}
string set (tmpvar const & tmp) const
@@ -427,9 +463,11 @@ struct mapvar
if (type() == pe_string)
return ("_stp_map_set_" + shortname(type()) + " (" + qname()
+ ", (" + tmp.qname() + "[0] ? " + tmp.qname() + " : NULL))");
- else
+ else if (type() == pe_long)
return ("_stp_map_set_" + shortname(type()) + " (" + qname()
+ ", " + tmp.qname() + ")");
+ else
+ throw semantic_error("setting a value of an unsupported map type");
}
string mangled_indices() const
@@ -445,6 +483,39 @@ struct mapvar
string init () const
{
+ if (type() == pe_stats)
+ {
+ switch (sdecl().type)
+ {
+ case statistic_decl::none:
+ assert(false);
+ break;
+
+ case statistic_decl::linear:
+ // FIXME: check for "reasonable" values in linear stats
+ return (qname()
+ + " = _stp_map_new"
+ + mangled_indices()
+ + " (MAXMAPENTRIES, HSTAT_LINEAR"
+ + ", " + stringify(sdecl().linear_low)
+ + ", " + stringify(sdecl().linear_high)
+ + ", " + stringify(sdecl().linear_step)
+ + ");");
+ break;
+
+ case statistic_decl::logarithmic:
+ if (sdecl().logarithmic_buckets > 64)
+ throw semantic_error("Cannot support > 64 logarithmic buckets");
+ return (qname()
+ + " = _stp_map_new"
+ + mangled_indices()
+ + " (MAXMAPENTRIES, HSTAT_LOG"
+ + ", " + stringify(sdecl().logarithmic_buckets)
+ + ");");
+ break;
+ }
+ }
+
return (qname() + " = _stp_map_new" + mangled_indices()
+ " (MAXMAPENTRIES, " + value_typename (type()) + ");");
}
@@ -578,7 +649,6 @@ c_unparser::emit_common_header ()
// XXX: tapsets.cxx should be able to add additional definitions
o->newline() << "typedef char string_t[MAXSTRINGLEN];";
- o->newline() << "typedef struct { } stats_t;";
o->newline();
o->newline() << "#define STAP_SESSION_STARTING 0";
o->newline() << "#define STAP_SESSION_RUNNING 1";
@@ -673,6 +743,9 @@ c_unparser::emit_common_header ()
o->newline(-1) << "} contexts [NR_CPUS];" << endl;
emit_map_type_instantiations ();
+
+ if (!session->stat_decls.empty())
+ o->newline() << "#include \"stat.c\"" << endl;
}
@@ -984,7 +1057,7 @@ mapvar::key_typename(exp_type e)
return "STRING";
break;
default:
- throw semantic_error("array type is neither string nor long");
+ throw semantic_error("array key is neither string nor long");
break;
}
}
@@ -1026,7 +1099,7 @@ c_unparser::emit_map_type_instantiations ()
for (set<exp_type>::const_iterator i = value_types.begin();
i != value_types.end(); ++i)
{
- string ktype = mapvar::key_typename(*i);
+ string ktype = mapvar::value_typename(*i);
o->newline() << "#define NEED_" << ktype << "_VALS";
}
@@ -1057,7 +1130,7 @@ c_unparser::c_typename (exp_type e)
{
case pe_long: return string("int64_t");
case pe_string: return string("string_t");
- case pe_stats: return string("stats_t");
+ case pe_stats: return string("Stat");
case pe_unknown:
default:
throw semantic_error ("cannot expand unknown type");
@@ -1074,7 +1147,7 @@ c_unparser::c_varname (const string& e)
void
c_unparser::c_assign (var& lvalue, const string& rvalue, const token *tok)
-{
+{
switch (lvalue.type())
{
case pe_string:
@@ -1084,7 +1157,7 @@ c_unparser::c_assign (var& lvalue, const string& rvalue, const token *tok)
o->newline() << lvalue << " = " << rvalue << ";";
break;
default:
- throw semantic_error ("unknown rvalue type in assignment", tok);
+ throw semantic_error ("unknown lvalue type in assignment", tok);
}
}
@@ -1173,6 +1246,14 @@ c_unparser_assignment::c_assignop(tmpvar & res,
throw semantic_error ("string assignment operator " +
op + " unsupported", tok);
}
+ else if (op == "<<<")
+ {
+ assert(lval.type() == pe_stats);
+ assert(rval.type() == pe_long);
+ assert(res.type() == pe_long);
+ o->newline() << res << " = " << rval << ";";
+ o->newline() << "_stp_stat_add (" << lval << ", " << res << ");";
+ }
else if (res.type() == pe_long)
{
// a lot of operators come through this "gate":
@@ -1189,8 +1270,6 @@ c_unparser_assignment::c_assignop(tmpvar & res,
macop = "*error*"; // special shortcuts below
else if (oplen > 1 && op[oplen-1] == '=') // for +=, %=, <<=, etc...
macop = op.substr(0, oplen-1);
- else if (op == "<<<")
- throw semantic_error ("stats aggregation not yet implemented", tok);
else if (op == "++")
macop = "+";
else if (op == "--")
@@ -1333,7 +1412,18 @@ c_unparser::gensym(exp_type ty)
var
c_unparser::getvar(vardecl *v, token const *tok)
{
- return var (is_local (v, tok), v->type, v->name);
+ bool loc = is_local (v, tok);
+ if (loc)
+ return var (loc, v->type, v->name);
+ else
+ {
+ statistic_decl sd;
+ std::map<std::string, statistic_decl>::const_iterator i;
+ i = session->stat_decls.find(v->name);
+ if (i != session->stat_decls.end())
+ sd = i->second;
+ return var (loc, v->type, sd, v->name);
+ }
}
@@ -1342,7 +1432,12 @@ c_unparser::getmap(vardecl *v, token const *tok)
{
if (v->arity < 1)
throw new semantic_error("attempt to use scalar where map expected", tok);
- return mapvar (is_local (v, tok), v->type, v->name, v->index_types);
+ statistic_decl sd;
+ std::map<std::string, statistic_decl>::const_iterator i;
+ i = session->stat_decls.find(v->name);
+ if (i != session->stat_decls.end())
+ sd = i->second;
+ return mapvar (is_local (v, tok), v->type, sd, v->name, v->index_types);
}
@@ -1963,12 +2058,27 @@ c_tmpcounter::visit_assignment (assignment *e)
void
c_unparser::visit_assignment (assignment* e)
{
- if (e->type != e->left->type)
- throw semantic_error ("type mismatch", e->tok,
- "vs", e->left->tok);
- if (e->right->type != e->left->type)
- throw semantic_error ("type mismatch", e->right->tok,
- "vs", e->left->tok);
+ if (e->op == "<<<")
+ {
+ if (e->type != pe_long)
+ throw semantic_error ("non-number <<< expression", e->tok);
+
+ if (e->left->type != pe_stats)
+ throw semantic_error ("non-stats left operand to <<< expression", e->left->tok);
+
+ if (e->right->type != pe_long)
+ throw semantic_error ("non-number right operand to <<< expression", e->right->tok);
+
+ }
+ else
+ {
+ if (e->type != e->left->type)
+ throw semantic_error ("type mismatch", e->tok,
+ "vs", e->left->tok);
+ if (e->right->type != e->left->type)
+ throw semantic_error ("type mismatch", e->right->tok,
+ "vs", e->left->tok);
+ }
c_unparser_assignment tav (this, e->op, e->right);
e->left->visit (& tav);
@@ -2054,8 +2164,9 @@ c_unparser::visit_symbol (symbol* e)
void
c_tmpcounter_assignment::visit_symbol (symbol *e)
{
- tmpvar tmp = parent->parent->gensym (e->type);
- tmpvar res = parent->parent->gensym (e->type);
+ exp_type ty = rvalue ? rvalue->type : e->type;
+ tmpvar tmp = parent->parent->gensym (ty);
+ tmpvar res = parent->parent->gensym (ty);
tmp.declare (*(parent->parent));
res.declare (*(parent->parent));
@@ -2091,8 +2202,9 @@ c_unparser_assignment::visit_symbol (symbol *e)
throw semantic_error ("unexpected reference to array", e->tok);
parent->o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
- tmpvar rval = parent->gensym (e->type);
- tmpvar res = parent->gensym (e->type);
+ exp_type ty = rvalue ? rvalue->type : e->type;
+ tmpvar rval = parent->gensym (ty);
+ tmpvar res = parent->gensym (ty);
prepare_rvalue (op, rval, e->tok);
@@ -2161,6 +2273,11 @@ c_unparser::load_map_indices(arrayindex *e,
void
c_unparser::visit_arrayindex (arrayindex* e)
{
+
+ // Visiting an statistic-valued array in a non-lvalue context is prohibited.
+ if (e->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
@@ -2211,13 +2328,14 @@ c_tmpcounter_assignment::visit_arrayindex (arrayindex *e)
}
// The expression rval, lval, and result.
- tmpvar rval = parent->parent->gensym (e->type);
+ exp_type ty = rvalue ? rvalue->type : e->type;
+ tmpvar rval = parent->parent->gensym (ty);
rval.declare (*(parent->parent));
- tmpvar lval = parent->parent->gensym (e->type);
+ tmpvar lval = parent->parent->gensym (ty);
lval.declare (*(parent->parent));
- tmpvar res = parent->parent->gensym (e->type);
+ tmpvar res = parent->parent->gensym (ty);
res.declare (*(parent->parent));
if (rvalue)
@@ -2241,14 +2359,14 @@ c_unparser_assignment::visit_arrayindex (arrayindex *e)
vector<tmpvar> idx;
parent->load_map_indices (e, idx);
- tmpvar rvar = parent->gensym (e->type);
- tmpvar lvar = parent->gensym (e->type);
- tmpvar res = parent->gensym (e->type);
+ exp_type ty = rvalue ? rvalue->type : e->type;
+ tmpvar rvar = parent->gensym (ty);
+ tmpvar lvar = parent->gensym (ty);
+ tmpvar res = parent->gensym (ty);
// NB: because these expressions are nestable, emit this construct
// thusly:
// ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs); lvar; res;
- // rvar = ...;
// lock (array);
// lvar = get (array,idx0...N); // if necessary
// assignop (res, lvar, rvar);
@@ -2259,19 +2377,49 @@ c_unparser_assignment::visit_arrayindex (arrayindex *e)
// we store all indices in temporary variables to avoid nasty
// reentrancy issues that pop up with nested expressions:
// e.g. ++a[a[c]=5] could deadlock
-
+ //
+ //
+ // There is an exception to the above form: if we're doign a <<< assigment to
+ // a statistic-valued map, there's a special form we follow:
+ //
+ // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs); lvar; res;
+ // lock (array);
+ // seek (array,idx0...N);
+ // _stp_map_add_stat (array, rvar);
+ // unlock (array);
+ // rvar; })
+ //
+ // To simplify variable-allocation rules, we assign rvar to lvar and
+ // res in this block as well, even though they are technically
+ // superfluous.
+
prepare_rvalue (op, rvar, e->tok);
-
- { // block used to control varlock_w lifespan
- mapvar mvar = parent->getmap (e->referent, e->tok);
- o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
- varlock_w guard (*parent, mvar);
- o->newline() << mvar.seek (idx) << ";";
- if (op != "=") // don't bother fetch slot if we will just overwrite it
- parent->c_assign (lvar, mvar.get(), e->tok);
- c_assignop (res, lvar, rvar, e->tok);
- o->newline() << mvar.set (lvar) << ";";
- }
+
+ if (op == "<<<")
+ {
+ assert (e->type == pe_stats);
+ assert (rvalue->type == pe_long);
+
+ mapvar mvar = parent->getmap (e->referent, e->tok);
+ o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
+ varlock_w guard (*parent, mvar);
+ o->newline() << mvar.seek (idx) << ";";
+ o->newline() << "_stp_map_add_stat (" << mvar << ", " << rvar << ");";
+ // dummy assignments
+ o->newline() << lvar << " = " << rvar << ";";
+ o->newline() << res << " = " << rvar << ";";
+ }
+ else
+ { // block used to control varlock_w lifespan
+ mapvar mvar = parent->getmap (e->referent, e->tok);
+ o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
+ varlock_w guard (*parent, mvar);
+ o->newline() << mvar.seek (idx) << ";";
+ if (op != "=") // don't bother fetch slot if we will just overwrite it
+ parent->c_assign (lvar, mvar.get(), e->tok);
+ c_assignop (res, lvar, rvar, e->tok);
+ o->newline() << mvar.set (lvar) << ";";
+ }
o->newline() << res << ";";
}