diff options
-rw-r--r-- | ChangeLog | 52 | ||||
-rw-r--r-- | elaborate.cxx | 27 | ||||
-rw-r--r-- | elaborate.h | 1 | ||||
-rw-r--r-- | parse.cxx | 57 | ||||
-rw-r--r-- | parse.h | 4 | ||||
-rw-r--r-- | staptree.h | 18 | ||||
-rwxr-xr-x | testsuite/semko/thirty.stp | 11 | ||||
-rwxr-xr-x | testsuite/semko/thirtyone.stp | 11 | ||||
-rwxr-xr-x | testsuite/semko/twentyeight.stp | 12 | ||||
-rwxr-xr-x | testsuite/semko/twentyfive.stp | 12 | ||||
-rwxr-xr-x | testsuite/semko/twentyfour.stp | 12 | ||||
-rwxr-xr-x | testsuite/semko/twentynine.stp | 11 | ||||
-rwxr-xr-x | testsuite/semko/twentyseven.stp | 17 | ||||
-rwxr-xr-x | testsuite/semko/twentysix.stp | 12 | ||||
-rw-r--r-- | translate.cxx | 232 |
15 files changed, 439 insertions, 50 deletions
@@ -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; @@ -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)); } @@ -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 (); @@ -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 << ";"; } |