LTP GCOV extension - code coverage report
Current view: directory - src - translate.cxx
Test: stap.info
Date: 2008-03-12 Instrumented lines: 2026
Code covered: 92.0 % Executed lines: 1864

       1                 : // translation pass
       2                 : // Copyright (C) 2005-2008 Red Hat Inc.
       3                 : // Copyright (C) 2005-2007 Intel Corporation.
       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.
       9                 : 
      10                 : #include "config.h"
      11                 : #include "staptree.h"
      12                 : #include "elaborate.h"
      13                 : #include "translate.h"
      14                 : #include "session.h"
      15                 : #include "tapsets.h"
      16                 : #include "util.h"
      17                 : 
      18                 : #include <cstdlib>
      19                 : #include <iostream>
      20                 : #include <set>
      21                 : #include <sstream>
      22                 : #include <string>
      23                 : #include <cassert>
      24                 : 
      25                 : extern "C" {
      26                 : #include <elfutils/libdwfl.h>
      27                 : }
      28                 : 
      29                 : using namespace std;
      30                 : 
      31                 : struct var;
      32                 : struct tmpvar;
      33                 : struct aggvar;
      34                 : struct mapvar;
      35                 : struct itervar;
      36                 : 
      37                 : struct c_unparser: public unparser, public visitor
      38                 : {
      39                 :   systemtap_session* session;
      40                 :   translator_output* o;
      41                 : 
      42                 :   derived_probe* current_probe;
      43                 :   functiondecl* current_function;
      44                 :   unsigned tmpvar_counter;
      45                 :   unsigned label_counter;
      46                 :   bool probe_or_function_needs_deref_fault_handler;
      47                 : 
      48                 :   varuse_collecting_visitor vcv_needs_global_locks;
      49                 : 
      50                 :   map<string, string> probe_contents;
      51                 : 
      52             283 :   c_unparser (systemtap_session* ss):
      53                 :     session (ss), o (ss->op), current_probe(0), current_function (0),
      54             283 :   tmpvar_counter (0), label_counter (0) {}
      55             283 :   ~c_unparser () {}
      56                 : 
      57                 :   void emit_map_type_instantiations ();
      58                 :   void emit_common_header ();
      59                 :   void emit_global (vardecl* v);
      60                 :   void emit_global_init (vardecl* v);
      61                 :   void emit_global_param (vardecl* v);
      62                 :   void emit_functionsig (functiondecl* v);
      63                 :   void emit_module_init ();
      64                 :   void emit_module_exit ();
      65                 :   void emit_function (functiondecl* v);
      66                 :   void emit_locks (const varuse_collecting_visitor& v);
      67                 :   void emit_probe (derived_probe* v);
      68                 :   void emit_unlocks (const varuse_collecting_visitor& v);
      69                 : 
      70                 :   // for use by stats (pmap) foreach
      71                 :   set<string> aggregations_active;
      72                 : 
      73                 :   // for use by looping constructs
      74                 :   vector<string> loop_break_labels;
      75                 :   vector<string> loop_continue_labels;
      76                 : 
      77                 :   string c_typename (exp_type e);
      78                 :   string c_varname (const string& e);
      79                 :   string c_expression (expression* e);
      80                 : 
      81                 :   void c_assign (var& lvalue, const string& rvalue, const token* tok);
      82                 :   void c_assign (const string& lvalue, expression* rvalue, const string& msg);
      83                 :   void c_assign (const string& lvalue, const string& rvalue, exp_type type,
      84                 :                  const string& msg, const token* tok);
      85                 : 
      86                 :   void c_declare(exp_type ty, const string &name);
      87                 :   void c_declare_static(exp_type ty, const string &name);
      88                 : 
      89                 :   void c_strcat (const string& lvalue, const string& rvalue);
      90                 :   void c_strcat (const string& lvalue, expression* rvalue);
      91                 : 
      92                 :   void c_strcpy (const string& lvalue, const string& rvalue);
      93                 :   void c_strcpy (const string& lvalue, expression* rvalue);
      94                 : 
      95                 :   bool is_local (vardecl const* r, token const* tok);
      96                 : 
      97                 :   tmpvar gensym(exp_type ty);
      98                 :   aggvar gensym_aggregate();
      99                 : 
     100                 :   var getvar(vardecl* v, token const* tok = NULL);
     101                 :   itervar getiter(symbol* s);
     102                 :   mapvar getmap(vardecl* v, token const* tok = NULL);
     103                 : 
     104                 :   void load_map_indices(arrayindex* e,
     105                 :                         vector<tmpvar> & idx);
     106                 : 
     107                 :   void load_aggregate (expression *e, aggvar & agg, bool pre_agg=false);
     108                 :   string histogram_index_check(var & vase, tmpvar & idx) const;
     109                 : 
     110                 :   void collect_map_index_types(vector<vardecl* > const & vars,
     111                 :                                set< pair<vector<exp_type>, exp_type> > & types);
     112                 : 
     113                 :   void visit_statement (statement* s, unsigned actions, bool stmtize);
     114                 : 
     115                 :   void visit_block (block* s);
     116                 :   void visit_embeddedcode (embeddedcode* s);
     117                 :   void visit_null_statement (null_statement* s);
     118                 :   void visit_expr_statement (expr_statement* s);
     119                 :   void visit_if_statement (if_statement* s);
     120                 :   void visit_for_loop (for_loop* s);
     121                 :   void visit_foreach_loop (foreach_loop* s);
     122                 :   void visit_return_statement (return_statement* s);
     123                 :   void visit_delete_statement (delete_statement* s);
     124                 :   void visit_next_statement (next_statement* s);
     125                 :   void visit_break_statement (break_statement* s);
     126                 :   void visit_continue_statement (continue_statement* s);
     127                 :   void visit_literal_string (literal_string* e);
     128                 :   void visit_literal_number (literal_number* e);
     129                 :   void visit_binary_expression (binary_expression* e);
     130                 :   void visit_unary_expression (unary_expression* e);
     131                 :   void visit_pre_crement (pre_crement* e);
     132                 :   void visit_post_crement (post_crement* e);
     133                 :   void visit_logical_or_expr (logical_or_expr* e);
     134                 :   void visit_logical_and_expr (logical_and_expr* e);
     135                 :   void visit_array_in (array_in* e);
     136                 :   void visit_comparison (comparison* e);
     137                 :   void visit_concatenation (concatenation* e);
     138                 :   void visit_ternary_expression (ternary_expression* e);
     139                 :   void visit_assignment (assignment* e);
     140                 :   void visit_symbol (symbol* e);
     141                 :   void visit_target_symbol (target_symbol* e);
     142                 :   void visit_arrayindex (arrayindex* e);
     143                 :   void visit_functioncall (functioncall* e);
     144                 :   void visit_print_format (print_format* e);
     145                 :   void visit_stat_op (stat_op* e);
     146                 :   void visit_hist_op (hist_op* e);
     147                 : };
     148                 : 
     149                 : // A shadow visitor, meant to generate temporary variable declarations
     150                 : // for function or probe bodies.  Member functions should exactly match
     151                 : // the corresponding c_unparser logic and traversal sequence,
     152                 : // to ensure interlocking naming and declaration of temp variables.
     153                 : struct c_tmpcounter: 
     154                 :   public traversing_visitor
     155            3359 : {
     156                 :   c_unparser* parent;
     157            3359 :   c_tmpcounter (c_unparser* p): 
     158            3359 :     parent (p) 
     159                 :   {
     160            3359 :     parent->tmpvar_counter = 0;
     161            3359 :   }
     162                 : 
     163                 :   void load_map_indices(arrayindex* e);
     164                 : 
     165                 :   void visit_block (block *s);
     166                 :   void visit_for_loop (for_loop* s);
     167                 :   void visit_foreach_loop (foreach_loop* s);
     168                 :   // void visit_return_statement (return_statement* s);
     169                 :   void visit_delete_statement (delete_statement* s);
     170                 :   void visit_binary_expression (binary_expression* e);
     171                 :   // void visit_unary_expression (unary_expression* e);
     172                 :   void visit_pre_crement (pre_crement* e);
     173                 :   void visit_post_crement (post_crement* e);
     174                 :   // void visit_logical_or_expr (logical_or_expr* e);
     175                 :   // void visit_logical_and_expr (logical_and_expr* e);
     176                 :   void visit_array_in (array_in* e);
     177                 :   // void visit_comparison (comparison* e);
     178                 :   void visit_concatenation (concatenation* e);
     179                 :   // void visit_ternary_expression (ternary_expression* e);
     180                 :   void visit_assignment (assignment* e);
     181                 :   void visit_arrayindex (arrayindex* e);
     182                 :   void visit_functioncall (functioncall* e);
     183                 :   void visit_print_format (print_format* e);
     184                 :   void visit_stat_op (stat_op* e);
     185                 : };
     186                 : 
     187                 : struct c_unparser_assignment: 
     188                 :   public throwing_visitor
     189            6458 : {
     190                 :   c_unparser* parent;
     191                 :   string op;
     192                 :   expression* rvalue;
     193                 :   bool post; // true == value saved before modify operator
     194            5709 :   c_unparser_assignment (c_unparser* p, const string& o, expression* e):
     195                 :     throwing_visitor ("invalid lvalue type"),
     196            5709 :     parent (p), op (o), rvalue (e), post (false) {}
     197             749 :   c_unparser_assignment (c_unparser* p, const string& o, bool pp):
     198                 :     throwing_visitor ("invalid lvalue type"),
     199             749 :     parent (p), op (o), rvalue (0), post (pp) {}
     200                 : 
     201                 :   void prepare_rvalue (string const & op, 
     202                 :                        tmpvar & rval,
     203                 :                        token const*  tok);
     204                 : 
     205                 :   void c_assignop(tmpvar & res, 
     206                 :                   var const & lvar, 
     207                 :                   tmpvar const & tmp,
     208                 :                   token const*  tok);
     209                 : 
     210                 :   // only symbols and arrayindex nodes are possible lvalues
     211                 :   void visit_symbol (symbol* e);
     212                 :   void visit_arrayindex (arrayindex* e);
     213                 : };
     214                 : 
     215                 : 
     216                 : struct c_tmpcounter_assignment: 
     217                 :   public traversing_visitor
     218                 : // leave throwing for illegal lvalues to the c_unparser_assignment instance
     219            6459 : {
     220                 :   c_tmpcounter* parent;
     221                 :   const string& op;
     222                 :   expression* rvalue;
     223                 :   bool post; // true == value saved before modify operator
     224            6459 :   c_tmpcounter_assignment (c_tmpcounter* p, const string& o, expression* e, bool pp = false):
     225            6459 :     parent (p), op (o), rvalue (e), post (pp) {}
     226                 : 
     227                 :   void prepare_rvalue (tmpvar & rval);
     228                 : 
     229                 :   void c_assignop(tmpvar & res);
     230                 : 
     231                 :   // only symbols and arrayindex nodes are possible lvalues
     232                 :   void visit_symbol (symbol* e);
     233                 :   void visit_arrayindex (arrayindex* e);
     234                 : };
     235                 : 
     236                 : 
     237                 : ostream & operator<<(ostream & o, var const & v);
     238                 : 
     239                 : 
     240                 : /*
     241                 :   Some clarification on the runtime structures involved in statistics:
     242                 :   
     243                 :   The basic type for collecting statistics in the runtime is struct
     244                 :   stat_data. This contains the count, min, max, sum, and possibly
     245                 :   histogram fields.
     246                 :   
     247                 :   There are two places struct stat_data shows up.
     248                 :   
     249                 :   1. If you declare a statistic variable of any sort, you want to make
     250                 :   a struct _Stat. A struct _Stat* is also called a Stat. Struct _Stat
     251                 :   contains a per-CPU array of struct stat_data values, as well as a
     252                 :   struct stat_data which it aggregates into. Writes into a Struct
     253                 :   _Stat go into the per-CPU struct stat. Reads involve write-locking
     254                 :   the struct _Stat, aggregating into its aggregate struct stat_data,
     255                 :   unlocking, read-locking the struct _Stat, then reading values out of
     256                 :   the aggregate and unlocking.
     257                 : 
     258                 :   2. If you declare a statistic-valued map, you want to make a
     259                 :   pmap. This is a per-CPU array of maps, each of which holds struct
     260                 :   stat_data values, as well as an aggregate *map*. Writes into a pmap
     261                 :   go into the per-CPU map. Reads involve write-locking the pmap,
     262                 :   aggregating into its aggregate map, unlocking, read-locking the
     263                 :   pmap, then reading values out of its aggregate (which is a normal
     264                 :   map) and unlocking.
     265                 : 
     266                 :   Because, at the moment, the runtime does not support the concept of
     267                 :   a statistic which collects multiple histogram types, we may need to
     268                 :   instantiate one pmap or struct _Stat for each histogram variation
     269                 :   the user wants to track.  
     270                 :  */
     271                 : 
     272                 : class var
     273           28733 : {
     274                 : 
     275                 : protected:
     276                 :   bool local;
     277                 :   exp_type ty;
     278                 :   statistic_decl sd;
     279                 :   string name;
     280                 : 
     281                 : public:
     282                 : 
     283            6321 :   var(bool local, exp_type ty, statistic_decl const & sd, string const & name)
     284            6321 :     : local(local), ty(ty), sd(sd), name(name)
     285            6321 :   {}
     286                 : 
     287           84039 :   var(bool local, exp_type ty, string const & name)
     288           84039 :     : local(local), ty(ty), name(name)
     289           84039 :   {}
     290                 : 
     291          113459 :   virtual ~var() {}
     292                 : 
     293                 :   bool is_local() const
     294                 :   {
     295                 :     return local;
     296                 :   }
     297                 : 
     298              25 :   statistic_decl const & sdecl() const
     299                 :   {
     300              25 :     return sd;
     301                 :   }
     302                 : 
     303             112 :   void assert_hist_compatible(hist_op const & hop)
     304                 :   {
     305                 :     // Semantic checks in elaborate should have caught this if it was
     306                 :     // false. This is just a double-check.
     307             112 :     switch (sd.type)
     308                 :       {
     309                 :       case statistic_decl::linear:
     310              53 :         assert(hop.htype == hist_linear);
     311              53 :         assert(hop.params.size() == 3);
     312              53 :         assert(hop.params[0] == sd.linear_low);
     313              53 :         assert(hop.params[1] == sd.linear_high);
     314              53 :         assert(hop.params[2] == sd.linear_step);
     315              53 :         break;
     316                 :       case statistic_decl::logarithmic:
     317              59 :         assert(hop.htype == hist_log);
     318              59 :         assert(hop.params.size() == 0);
     319              59 :         break;
     320                 :       case statistic_decl::none:
     321               0 :         assert(false);
     322                 :       }
     323             112 :   }
     324                 : 
     325           34124 :   exp_type type() const
     326                 :   {
     327           34124 :     return ty;
     328                 :   }
     329                 : 
     330           66663 :   string value() const
     331                 :   {
     332           66663 :     if (local)
     333           59809 :       return "l->" + name;
     334                 :     else
     335            6854 :       return "global.s_" + name;
     336                 :   }
     337                 : 
     338              78 :   virtual string hist() const
     339                 :   {
     340              78 :     assert (ty == pe_stats);
     341              78 :     assert (sd.type != statistic_decl::none);
     342              78 :     return "(&(" + value() + "->hist))";
     343                 :   }
     344                 : 
     345              21 :   virtual string buckets() const
     346                 :   {
     347              21 :     assert (ty == pe_stats);
     348              21 :     assert (sd.type != statistic_decl::none);
     349              21 :     return "(" + value() + "->hist.buckets)";
     350                 :   }
     351                 : 
     352            1262 :   string init() const
     353                 :   {
     354            1262 :     switch (type())
     355                 :       {
     356                 :       case pe_string:
     357             474 :         if (! local)
     358              18 :           return ""; // module_param
     359                 :         else
     360             456 :           return value() + "[0] = '\\0';";
     361                 :       case pe_long:
     362             747 :         if (! local)
     363              98 :           return ""; // module_param
     364                 :         else
     365             649 :           return value() + " = 0;";
     366                 :       case pe_stats:
     367                 :         {
     368                 :           // See also mapvar::init().
     369                 :           
     370              41 :           string prefix = value() + " = _stp_stat_init (";
     371                 :           // Check for errors during allocation.
     372              82 :           string suffix = "if (" + value () + " == NULL) rc = -ENOMEM;";
     373                 :           
     374              41 :           switch (sd.type)
     375                 :             {
     376                 :             case statistic_decl::none:
     377               5 :               prefix += "HIST_NONE";
     378               5 :               break;
     379                 :               
     380                 :             case statistic_decl::linear:
     381                 :               prefix += string("HIST_LINEAR")
     382                 :                 + ", " + stringify(sd.linear_low) 
     383                 :                 + ", " + stringify(sd.linear_high) 
     384              22 :                 + ", " + stringify(sd.linear_step);
     385              22 :               break;
     386                 :               
     387                 :             case statistic_decl::logarithmic:
     388              14 :               prefix += string("HIST_LOG");
     389              14 :               break;
     390                 :               
     391                 :             default:
     392               0 :               throw semantic_error("unsupported stats type for " + value());
     393                 :             }
     394                 :           
     395              41 :           prefix = prefix + "); ";
     396              41 :           return string (prefix + suffix);
     397                 :         }
     398                 :         
     399                 :       default:
     400               0 :         throw semantic_error("unsupported initializer for " + value());
     401                 :       }
     402                 :   }
     403                 : 
     404             314 :   string fini () const
     405                 :   {
     406             314 :     switch (type())
     407                 :       {
     408                 :       case pe_string:
     409                 :       case pe_long:
     410             232 :         return ""; // no action required
     411                 :       case pe_stats:
     412              82 :         return "_stp_stat_del (" + value () + ");";
     413                 :       default:
     414               0 :         throw semantic_error("unsupported deallocator for " + value());
     415                 :       }
     416                 :   }
     417                 : 
     418           19999 :   void declare(c_unparser &c) const
     419                 :   {
     420           19999 :     c.c_declare(ty, name);
     421           19999 :   }
     422                 : };
     423                 : 
     424           14124 : ostream & operator<<(ostream & o, var const & v)
     425                 : {
     426           14124 :   return o << v.value();
     427                 : }
     428                 : 
     429                 : struct stmt_expr
     430                 : {
     431                 :   c_unparser & c;
     432           20282 :   stmt_expr(c_unparser & c) : c(c) 
     433                 :   {
     434           20282 :     c.o->newline() << "({";
     435           20282 :     c.o->indent(1);
     436           20282 :   }
     437           20282 :   ~stmt_expr()
     438                 :   {
     439           20282 :     c.o->newline(-1) << "})";
     440           20282 :   }
     441                 : };
     442                 : 
     443                 : 
     444                 : struct tmpvar
     445                 :   : public var
     446          120913 : {
     447                 : protected:
     448                 :   bool overridden;
     449                 :   string override_value;
     450                 : 
     451                 : public:
     452                 :   tmpvar(exp_type ty, 
     453           69239 :          unsigned & counter) 
     454           69239 :     : var(true, ty, ("__tmp" + stringify(counter++))), overridden(false)
     455           69239 :   {}
     456                 : 
     457             158 :   tmpvar(const var& source)
     458             158 :     : var(source), overridden(false)
     459             158 :   {}
     460                 : 
     461            8443 :   void override(const string &value)
     462                 :   {
     463            8443 :     overridden = true;
     464            8443 :     override_value = value;
     465            8443 :   }
     466                 : 
     467           53157 :   string value() const
     468                 :   {
     469           53157 :     if (overridden)
     470           11109 :       return override_value;
     471                 :     else
     472           42048 :       return var::value();
     473                 :   }  
     474                 : };
     475                 : 
     476           11644 : ostream & operator<<(ostream & o, tmpvar const & v)
     477                 : {
     478           11644 :   return o << v.value();
     479                 : }
     480                 : 
     481                 : struct aggvar
     482                 :   : public var
     483             632 : {
     484             632 :   aggvar(unsigned & counter) 
     485             632 :     : var(true, pe_stats, ("__tmp" + stringify(counter++)))
     486             632 :   {}
     487                 : 
     488                 :   string init() const
     489                 :   {
     490                 :     assert (type() == pe_stats);
     491                 :     return value() + " = NULL;";
     492                 :   }
     493                 : 
     494             316 :   void declare(c_unparser &c) const
     495                 :   {
     496             316 :     assert (type() == pe_stats);
     497             316 :     c.o->newline() << "struct stat_data *" << name << ";";
     498             316 :   }
     499                 : };
     500                 : 
     501                 : struct mapvar
     502                 :   : public var
     503            2974 : {
     504                 :   vector<exp_type> index_types;
     505                 :   int maxsize;
     506                 :   mapvar (bool local, exp_type ty, 
     507                 :           statistic_decl const & sd,
     508                 :           string const & name, 
     509                 :           vector<exp_type> const & index_types,
     510            2974 :           int maxsize)
     511                 :     : var (local, ty, sd, name),
     512                 :       index_types (index_types),
     513            2974 :       maxsize (maxsize)
     514            2974 :   {}
     515                 :   
     516                 :   static string shortname(exp_type e);
     517                 :   static string key_typename(exp_type e);
     518                 :   static string value_typename(exp_type e);
     519                 : 
     520            2520 :   string keysym () const
     521                 :   {
     522            2520 :     string result;
     523            2520 :     vector<exp_type> tmp = index_types;
     524            2520 :     tmp.push_back (type ());
     525            7998 :     for (unsigned i = 0; i < tmp.size(); ++i)
     526                 :       {
     527            5478 :         switch (tmp[i])
     528                 :           {
     529                 :           case pe_long:
     530            3840 :             result += 'i';
     531            3840 :             break;
     532                 :           case pe_string:
     533            1422 :             result += 's';
     534            1422 :             break;
     535                 :           case pe_stats:
     536             216 :             result += 'x';
     537             216 :             break;
     538                 :           default:
     539               0 :             throw semantic_error("unknown type of map");
     540                 :             break;
     541                 :           }
     542                 :       }
     543            2520 :     return result;
     544                 :   }
     545                 : 
     546            2246 :   string call_prefix (string const & fname, vector<tmpvar> const & indices, bool pre_agg=false) const
     547                 :   {
     548            2246 :     string mtype = (is_parallel() && !pre_agg) ? "pmap" : "map";
     549            4492 :     string result = "_stp_" + mtype + "_" + fname + "_" + keysym() + " (";
     550            2246 :     result += pre_agg? fetch_existing_aggregate() : value();
     551            4817 :     for (unsigned i = 0; i < indices.size(); ++i)
     552                 :       {
     553            2571 :         if (indices[i].type() != index_types[i])
     554               0 :           throw semantic_error("index type mismatch");
     555            2571 :         result += ", ";
     556            2571 :         result += indices[i].value();
     557                 :       }
     558                 : 
     559            2246 :     return result;
     560                 :   }
     561                 : 
     562            3779 :   bool is_parallel() const
     563                 :   {
     564            3779 :     return type() == pe_stats;
     565                 :   }
     566                 : 
     567              23 :   string calculate_aggregate() const
     568                 :   {
     569              23 :     if (!is_parallel())
     570               0 :       throw semantic_error("aggregating non-parallel map type");
     571                 :     
     572              23 :     return "_stp_pmap_agg (" + value() + ")";
     573                 :   }
     574                 : 
     575             159 :   string fetch_existing_aggregate() const
     576                 :   {
     577             159 :     if (!is_parallel())
     578               0 :       throw semantic_error("fetching aggregate of non-parallel map type");
     579                 :     
     580             159 :     return "_stp_pmap_get_agg(" + value() + ")";
     581                 :   }
     582                 : 
     583             180 :   string del (vector<tmpvar> const & indices) const
     584                 :   {
     585             180 :     return (call_prefix("del", indices) + ")");
     586                 :   }
     587                 : 
     588              42 :   string exists (vector<tmpvar> const & indices) const
     589                 :   {
     590              42 :     if (type() == pe_long || type() == pe_string)
     591              42 :       return (call_prefix("exists", indices) + ")");
     592               0 :     else if (type() == pe_stats)
     593                 :       return ("((uintptr_t)" + call_prefix("get", indices)
     594               0 :               + ") != (uintptr_t) 0)");
     595                 :     else
     596               0 :       throw semantic_error("checking existence of an unsupported map type");
     597                 :   }
     598                 : 
     599            1001 :   string get (vector<tmpvar> const & indices, bool pre_agg=false) const
     600                 :   {
     601                 :     // see also itervar::get_key
     602            1001 :     if (type() == pe_string)
     603                 :         // impedance matching: NULL -> empty strings
     604                 :       return ("({ char *v = " + call_prefix("get", indices, pre_agg) + ");"
     605             380 :               + "if (!v) v = \"\"; v; })");
     606             621 :     else if (type() == pe_long || type() == pe_stats)
     607             621 :       return call_prefix("get", indices, pre_agg) + ")";
     608                 :     else
     609               0 :       throw semantic_error("getting a value from an unsupported map type");
     610                 :   }
     611                 : 
     612              65 :   string add (vector<tmpvar> const & indices, tmpvar const & val) const
     613                 :   {
     614              65 :     string res = "{ int rc = ";
     615                 : 
     616                 :     // impedance matching: empty strings -> NULL
     617              65 :     if (type() == pe_stats)
     618              65 :       res += (call_prefix("add", indices) + ", " + val.value() + ")");
     619                 :     else
     620               0 :       throw semantic_error("adding a value of an unsupported map type");
     621                 : 
     622                 :     res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " +
     623                 :       stringify(maxsize > 0 ?
     624                 :           "size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES")
     625              65 :       + "\"; }";
     626                 : 
     627               0 :     return res;
     628                 :   }
     629                 : 
     630             958 :   string set (vector<tmpvar> const & indices, tmpvar const & val) const
     631                 :   {
     632             958 :     string res = "{ int rc = ";
     633                 : 
     634                 :     // impedance matching: empty strings -> NULL
     635             958 :     if (type() == pe_string)
     636                 :       res += (call_prefix("set", indices) 
     637             572 :               + ", (" + val.value() + "[0] ? " + val.value() + " : NULL))");
     638             386 :     else if (type() == pe_long)
     639             386 :       res += (call_prefix("set", indices) + ", " + val.value() + ")");
     640                 :     else
     641               0 :       throw semantic_error("setting a value of an unsupported map type");
     642                 : 
     643                 :     res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " +
     644                 :       stringify(maxsize > 0 ?
     645                 :           "size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES")
     646             958 :       + "\"; }";
     647                 : 
     648               0 :     return res;
     649                 :   }
     650                 : 
     651               9 :   string hist() const
     652                 :   {
     653               9 :     assert (ty == pe_stats);
     654               9 :     assert (sd.type != statistic_decl::none);
     655               9 :     return "(&(" + fetch_existing_aggregate() + "->hist))";
     656                 :   }
     657                 : 
     658               4 :   string buckets() const
     659                 :   {
     660               4 :     assert (ty == pe_stats);
     661               4 :     assert (sd.type != statistic_decl::none);
     662               4 :     return "(" + fetch_existing_aggregate() + "->hist.buckets)";
     663                 :   }
     664                 :                 
     665             274 :   string init () const
     666                 :   {
     667             274 :     string mtype = is_parallel() ? "pmap" : "map";
     668                 :     string prefix = value() + " = _stp_" + mtype + "_new_" + keysym() + " (" + 
     669             293 :       (maxsize > 0 ? stringify(maxsize) : "MAXMAPENTRIES") ;
     670                 : 
     671                 :     // See also var::init().
     672                 : 
     673                 :     // Check for errors during allocation.
     674             274 :     string suffix = "if (" + value () + " == NULL) rc = -ENOMEM;";
     675                 : 
     676             274 :     if (type() == pe_stats)
     677                 :       {
     678              25 :         switch (sdecl().type)
     679                 :           {
     680                 :           case statistic_decl::none:
     681              18 :             prefix = prefix + ", HIST_NONE";
     682              18 :             break;
     683                 : 
     684                 :           case statistic_decl::linear:
     685                 :             // FIXME: check for "reasonable" values in linear stats
     686                 :             prefix = prefix + ", HIST_LINEAR" 
     687                 :               + ", " + stringify(sdecl().linear_low) 
     688                 :               + ", " + stringify(sdecl().linear_high) 
     689               0 :               + ", " + stringify(sdecl().linear_step);
     690               0 :             break;
     691                 : 
     692                 :           case statistic_decl::logarithmic:
     693               7 :             prefix = prefix + ", HIST_LOG";
     694                 :             break;
     695                 :           }
     696                 :       }
     697                 : 
     698             274 :     prefix = prefix + "); ";
     699             274 :     return (prefix + suffix);
     700                 :   }
     701                 : 
     702             548 :   string fini () const
     703                 :   {
     704                 :     // NB: fini() is safe to call even for globals that have not
     705                 :     // successfully initialized (that is to say, on NULL pointers),
     706                 :     // because the runtime specifically tolerates that in its _del
     707                 :     // functions.
     708                 : 
     709             548 :     if (is_parallel())
     710              50 :       return "_stp_pmap_del (" + value() + ");";
     711                 :     else
     712             498 :       return "_stp_map_del (" + value() + ");";
     713                 :   }
     714                 : };
     715                 : 
     716                 : 
     717                 : class itervar
     718             204 : {
     719                 :   exp_type referent_ty;
     720                 :   string name;
     721                 : 
     722                 : public:
     723                 : 
     724             204 :   itervar (symbol* e, unsigned & counter)
     725                 :     : referent_ty(e->referent->type), 
     726             204 :       name("__tmp" + stringify(counter++))
     727                 :   {
     728             204 :     if (referent_ty == pe_unknown)
     729               0 :       throw semantic_error("iterating over unknown reference type", e->tok);
     730             204 :   }
     731                 :   
     732             102 :   string declare () const
     733                 :   {
     734             102 :     return "struct map_node *" + name + ";";
     735                 :   }
     736                 :   
     737             102 :   string start (mapvar const & mv) const
     738                 :   {
     739             102 :     string res;
     740                 : 
     741             102 :     if (mv.type() != referent_ty)
     742               0 :       throw semantic_error("inconsistent iterator type in itervar::start()");
     743                 :     
     744             102 :     if (mv.is_parallel())
     745              23 :       return "_stp_map_start (" + mv.fetch_existing_aggregate() + ")";
     746                 :     else
     747              79 :       return "_stp_map_start (" + mv.value() + ")";
     748                 :   }
     749                 : 
     750             102 :   string next (mapvar const & mv) const
     751                 :   {
     752             102 :     if (mv.type() != referent_ty)
     753               0 :       throw semantic_error("inconsistent iterator type in itervar::next()");
     754                 : 
     755             102 :     if (mv.is_parallel())
     756              23 :       return "_stp_map_iter (" + mv.fetch_existing_aggregate() + ", " + value() + ")";
     757                 :     else
     758              79 :       return "_stp_map_iter (" + mv.value() + ", " + value() + ")";
     759                 :   }
     760                 : 
     761             532 :   string value () const
     762                 :   {
     763             532 :     return "l->" + name;
     764                 :   }
     765                 :   
     766             124 :   string get_key (exp_type ty, unsigned i) const
     767                 :   {
     768                 :     // bug translator/1175: runtime uses base index 1 for the first dimension
     769                 :     // see also mapval::get
     770             124 :     switch (ty)
     771                 :       {
     772                 :       case pe_long:
     773              91 :         return "_stp_key_get_int64 ("+ value() + ", " + stringify(i+1) + ")";
     774                 :       case pe_string:
     775                 :         // impedance matching: NULL -> empty strings
     776                 :         return "({ char *v = "
     777                 :           "_stp_key_get_str ("+ value() + ", " + stringify(i+1) + "); "
     778                 :           "if (! v) v = \"\"; "
     779              33 :           "v; })";
     780                 :       default:
     781               0 :         throw semantic_error("illegal key type");
     782                 :       }
     783                 :   }
     784                 : };
     785                 : 
     786             306 : ostream & operator<<(ostream & o, itervar const & v)
     787                 : {
     788             306 :   return o << v.value();
     789                 : }
     790                 : 
     791                 : // ------------------------------------------------------------------------
     792                 : 
     793                 : 
     794            5023 : translator_output::translator_output (ostream& f):
     795            5023 :   buf(0), o2 (0), o (f), tablevel (0)
     796                 : {
     797            5023 : }
     798                 : 
     799                 : 
     800             283 : translator_output::translator_output (const string& filename, size_t bufsize):
     801                 :   buf (new char[bufsize]),
     802                 :   o2 (new ofstream (filename.c_str ())), 
     803                 :   o (*o2), 
     804             283 :   tablevel (0)
     805                 : {
     806             283 :   o2->rdbuf()->pubsetbuf(buf, bufsize);
     807             283 : }
     808                 : 
     809                 : 
     810            5306 : translator_output::~translator_output ()
     811                 : {
     812            5306 :   delete o2;
     813            5306 :   delete [] buf;
     814            5306 : }
     815                 : 
     816                 : 
     817                 : ostream&
     818          567817 : translator_output::newline (int indent)
     819                 : {
     820          567817 :   if (!  (indent > 0 || tablevel >= (unsigned)-indent)) o.flush ();
     821          567817 :   assert (indent > 0 || tablevel >= (unsigned)-indent);
     822                 : 
     823          567817 :   tablevel += indent;
     824          567817 :   o << "\n";
     825         1939793 :   for (unsigned i=0; i<tablevel; i++)
     826         1371976 :     o << "  ";
     827          567817 :   return o;
     828                 : }
     829                 : 
     830                 : 
     831                 : void
     832           90379 : translator_output::indent (int indent)
     833                 : {
     834           90379 :   if (!  (indent > 0 || tablevel >= (unsigned)-indent)) o.flush ();
     835           90379 :   assert (indent > 0 || tablevel >= (unsigned)-indent);
     836           90379 :   tablevel += indent;
     837           90379 : }
     838                 : 
     839                 : 
     840                 : ostream&
     841          182594 : translator_output::line ()
     842                 : {
     843          182594 :   return o;
     844                 : }
     845                 : 
     846                 : 
     847                 : // ------------------------------------------------------------------------
     848                 : 
     849                 : void
     850             283 : c_unparser::emit_common_header ()
     851                 : {
     852             283 :   o->newline() << "typedef char string_t[MAXSTRINGLEN];";
     853             283 :   o->newline();
     854             283 :   o->newline() << "#define STAP_SESSION_STARTING 0";
     855             283 :   o->newline() << "#define STAP_SESSION_RUNNING 1";
     856             283 :   o->newline() << "#define STAP_SESSION_ERROR 2";
     857             283 :   o->newline() << "#define STAP_SESSION_STOPPING 3";
     858             283 :   o->newline() << "#define STAP_SESSION_STOPPED 4";
     859             283 :   o->newline() << "atomic_t session_state = ATOMIC_INIT (STAP_SESSION_STARTING);";
     860             283 :   o->newline() << "atomic_t error_count = ATOMIC_INIT (0);";
     861             283 :   o->newline() << "atomic_t skipped_count = ATOMIC_INIT (0);";
     862             283 :   o->newline();
     863             283 :   o->newline() << "struct context {";
     864             283 :   o->newline(1) << "atomic_t busy;";
     865             283 :   o->newline() << "const char *probe_point;";
     866             283 :   o->newline() << "int actionremaining;";
     867             283 :   o->newline() << "unsigned nesting;";
     868             283 :   o->newline() << "string_t error_buffer;";
     869             283 :   o->newline() << "const char *last_error;";
     870                 :   // NB: last_error is used as a health flag within a probe.
     871                 :   // While it's 0, execution continues
     872                 :   // When it's "", current function or probe unwinds and returns early
     873                 :   // When it's "something", probe code unwinds, _stp_error's, sets error state
     874                 :   // See c_unparser::visit_statement()
     875             283 :   o->newline() << "const char *last_stmt;";
     876             283 :   o->newline() << "struct pt_regs *regs;";
     877             283 :   o->newline() << "struct kretprobe_instance *pi;";
     878             283 :   o->newline() << "va_list *mark_va_list;";
     879             283 :   o->newline() << "void *data;";
     880             283 :   o->newline() << "#ifdef STP_TIMING";
     881             283 :   o->newline() << "Stat *statp;";
     882             283 :   o->newline() << "#endif";
     883             283 :   o->newline() << "#ifdef STP_OVERLOAD";
     884             283 :   o->newline() << "cycles_t cycles_base;";
     885             283 :   o->newline() << "cycles_t cycles_sum;";
     886             283 :   o->newline() << "#endif";
     887             283 :   o->newline() << "union {";
     888             283 :   o->indent(1);
     889                 : 
     890                 :   // To elide context variables for probe handler functions that
     891                 :   // themselves are about to get duplicate-eliminated, we XXX
     892                 :   // duplicate the parse-tree-hash method from ::emit_probe().
     893             283 :   map<string, string> tmp_probe_contents;
     894                 :   // The reason we don't use c_unparser::probe_contents itself
     895                 :   // for this is that we don't want to muck up the data for
     896                 :   // that later routine.
     897                 : 
     898            9538 :   for (unsigned i=0; i<session->probes.size(); i++)
     899                 :     {
     900            9256 :       derived_probe* dp = session->probes[i];
     901                 : 
     902                 :       // NB: see c_unparser::emit_probe() for original copy of duplicate-hashing logic.
     903            9256 :       ostringstream oss;
     904            9256 :       oss << "c->statp = & time_" << dp->basest()->name << ";" << endl;  // -t anti-dupe
     905            9256 :       oss << "# needs_global_locks: " << dp->needs_global_locks () << endl;
     906            9256 :       dp->body->print(oss);
     907                 :       // NB: dependent probe conditions *could* be listed here, but don't need to be.
     908                 :       // That's because they're only dependent on the probe body, which is already
     909                 :       // "hashed" in above.
     910                 : 
     911                 : 
     912            9256 :       if (tmp_probe_contents.count(oss.str()) == 0) // unique
     913                 :         {
     914            2117 :           tmp_probe_contents[oss.str()] = dp->name; // save it
     915                 : 
     916                 :           // XXX: probe locals need not be recursion-nested, only function locals
     917                 :           
     918            2117 :           o->newline() << "struct " << dp->name << "_locals {";
     919            2117 :           o->indent(1);
     920           13414 :           for (unsigned j=0; j<dp->locals.size(); j++)
     921                 :             {
     922            4590 :               vardecl* v = dp->locals[j];
     923                 :               try 
     924                 :                 {
     925                 :                   o->newline() << c_typename (v->type) << " " 
     926            4590 :                                << c_varname (v->name) << ";";
     927               0 :                 } catch (const semantic_error& e) {
     928               0 :                 semantic_error e2 (e);
     929               0 :                 if (e2.tok1 == 0) e2.tok1 = v->tok;
     930               0 :                 throw e2;
     931                 :               }
     932                 :             }
     933                 : 
     934                 :           // NB: This part is finicky.  The logic here must
     935                 :           // match up with 
     936            2117 :           c_tmpcounter ct (this);
     937            2117 :           dp->emit_probe_context_vars (o);
     938            2117 :           dp->body->visit (& ct);
     939                 : 
     940            2116 :           o->newline(-1) << "} " << dp->name << ";";
     941                 :         }
     942                 :     }
     943                 : 
     944            1524 :   for (unsigned i=0; i<session->functions.size(); i++)
     945                 :     {
     946            1242 :       functiondecl* fd = session->functions[i];
     947                 :       o->newline()
     948            1242 :         << "struct function_" << c_varname (fd->name) << "_locals {";
     949            1242 :       o->indent(1);
     950            2638 :       for (unsigned j=0; j<fd->locals.size(); j++)
     951                 :         {
     952              77 :           vardecl* v = fd->locals[j];
     953                 :           try 
     954                 :             {
     955                 :               o->newline() << c_typename (v->type) << " " 
     956              77 :                            << c_varname (v->name) << ";";
     957               0 :             } catch (const semantic_error& e) {
     958               0 :               semantic_error e2 (e);
     959               0 :               if (e2.tok1 == 0) e2.tok1 = v->tok;
     960               0 :               throw e2;
     961                 :             }
     962                 :         }
     963            4058 :       for (unsigned j=0; j<fd->formal_args.size(); j++)
     964                 :         {
     965             787 :           vardecl* v = fd->formal_args[j];
     966                 :           try 
     967                 :             {
     968                 :               o->newline() << c_typename (v->type) << " " 
     969             787 :                            << c_varname (v->name) << ";";
     970               0 :             } catch (const semantic_error& e) {
     971               0 :               semantic_error e2 (e);
     972               0 :               if (e2.tok1 == 0) e2.tok1 = v->tok;
     973               0 :               throw e2;
     974                 :             }
     975                 :         }
     976            1242 :       c_tmpcounter ct (this);
     977            1242 :       fd->body->visit (& ct);
     978            1242 :       if (fd->type == pe_unknown)
     979             214 :         o->newline() << "/* no return value */";
     980                 :       else
     981                 :         {
     982            1028 :           o->newline() << c_typename (fd->type) << " __retvalue;";
     983                 :         }
     984            1242 :       o->newline(-1) << "} function_" << c_varname (fd->name) << ";";
     985                 :     }
     986             282 :   o->newline(-1) << "} locals [MAXNESTING];";
     987             282 :   o->newline(-1) << "};\n";
     988             282 :   o->newline() << "void *contexts = NULL; /* alloc_percpu */\n";
     989                 : 
     990             282 :   emit_map_type_instantiations ();
     991                 : 
     992             282 :   if (!session->stat_decls.empty())
     993              46 :     o->newline() << "#include \"stat.c\"\n";
     994                 : 
     995             283 :   o->newline();
     996             282 : }
     997                 : 
     998                 : 
     999                 : void
    1000             431 : c_unparser::emit_global_param (vardecl *v)
    1001                 : {
    1002             431 :   string vn = c_varname (v->name);
    1003                 : 
    1004                 :   // NB: systemtap globals can collide with linux macros,
    1005                 :   // e.g. VM_FAULT_MAJOR.  We want the parameter name anyway.  This
    1006                 :   // #undef is spit out at the end of the C file, so that removing the
    1007                 :   // definition won't affect any other embedded-C or generated code.
    1008                 :   // XXX: better not have a global variable named module_param_named etc.!
    1009             431 :   o->newline() << "#undef " << vn;
    1010                 : 
    1011                 :   // Emit module_params for this global, if its type is convenient.
    1012             529 :   if (v->arity == 0 && v->type == pe_long)
    1013                 :     {
    1014                 :       o->newline() << "module_param_named (" << vn << ", "
    1015              98 :                    << "global.s_" << vn << ", int64_t, 0);";
    1016                 :     }
    1017             333 :   else if (v->arity == 0 && v->type == pe_string)
    1018                 :     {
    1019                 :       // NB: no special copying is needed.
    1020                 :       o->newline() << "module_param_string (" << vn << ", "
    1021                 :                    << "global.s_" << vn
    1022              18 :                    << ", MAXSTRINGLEN, 0);";
    1023             431 :     }
    1024             431 : }
    1025                 : 
    1026                 : 
    1027                 : void
    1028             431 : c_unparser::emit_global (vardecl *v)
    1029                 : {
    1030             431 :   string vn = c_varname (v->name);
    1031                 : 
    1032             431 :   if (v->arity == 0)
    1033             157 :     o->newline() << c_typename (v->type) << " s_" << vn << ";";
    1034             274 :   else if (v->type == pe_stats)
    1035              25 :     o->newline() << "PMAP s_" << vn << ";";
    1036                 :   else
    1037             249 :     o->newline() << "MAP s_" << vn << ";";
    1038             431 :   o->newline() << "rwlock_t s_" << vn << "_lock;";
    1039             431 : }
    1040                 : 
    1041                 : 
    1042                 : void
    1043             431 : c_unparser::emit_global_init (vardecl *v)
    1044                 : {
    1045             431 :   string vn = c_varname (v->name);
    1046                 : 
    1047             431 :   if (v->arity == 0) // can only statically initialize some scalars
    1048                 :     {
    1049             157 :       if (v->init)
    1050                 :         {
    1051              15 :           o->line() << ".s_" << vn << " = ";
    1052              15 :           v->init->visit(this);
    1053              15 :           o->line() << ",";
    1054                 :         }
    1055             431 :     }
    1056             431 : }
    1057                 : 
    1058                 : 
    1059                 : 
    1060                 : void
    1061            1242 : c_unparser::emit_functionsig (functiondecl* v)
    1062                 : {
    1063                 :   o->newline() << "static void function_" << v->name
    1064            1242 :                << " (struct context * __restrict__ c);";
    1065            1242 : }
    1066                 : 
    1067                 : 
    1068                 : 
    1069                 : void
    1070             281 : c_unparser::emit_module_init ()
    1071                 : {
    1072             281 :   vector<derived_probe_group*> g = all_session_groups (*session);
    1073             656 :   for (unsigned i=0; i<g.size(); i++)
    1074             375 :     g[i]->emit_module_decls (*session);
    1075                 :   
    1076             281 :   o->newline();
    1077             281 :   o->newline() << "int systemtap_module_init (void) {";
    1078             281 :   o->newline(1) << "int rc = 0;";
    1079             281 :   o->newline() << "int i=0, j=0;"; // for derived_probe_group use
    1080             281 :   o->newline() << "const char *probe_point = \"\";";
    1081                 : 
    1082                 :   // Compare actual and targeted kernel releases/machines.  Sometimes
    1083                 :   // one may install the incorrect debuginfo or -devel RPM, and try to
    1084                 :   // run a probe compiled for a different version.  Catch this early,
    1085                 :   // just in case modversions didn't.
    1086             281 :   o->newline() << "down_read (& uts_sem);";
    1087             281 :   o->newline() << "{";
    1088             281 :   o->indent(1);
    1089                 : 
    1090                 :   // Args, linux 2.6.19+ did a switcheroo on system_utsname to utsname().
    1091             281 :   o->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)";
    1092             281 :   o->newline() << "const char* machine = utsname()->machine;";
    1093             281 :   o->newline() << "const char* release = utsname()->release;";
    1094             281 :   o->newline() << "#else";
    1095             281 :   o->newline() << "const char* machine = system_utsname.machine;";
    1096             281 :   o->newline() << "const char* release = system_utsname.release;";
    1097             281 :   o->newline() << "#endif";
    1098                 : 
    1099                 :   o->newline() << "if (strcmp (machine, "
    1100             281 :                << lex_cast_qstring (session->architecture) << ")) {";
    1101                 :   o->newline(1) << "_stp_error (\"module machine mismatch (%s vs %s)\", "
    1102                 :                 << "machine, "
    1103                 :                 << lex_cast_qstring (session->architecture)
    1104             281 :                 << ");";
    1105             281 :   o->newline() << "rc = -EINVAL;";
    1106             281 :   o->newline(-1) << "}";
    1107                 : 
    1108                 :   o->newline() << "if (strcmp (release, "
    1109             281 :                << lex_cast_qstring (session->kernel_release) << ")) {";
    1110                 :   o->newline(1) << "_stp_error (\"module release mismatch (%s vs %s)\", "
    1111                 :                 << "release, "
    1112                 :                 << lex_cast_qstring (session->kernel_release)
    1113             281 :                 << ");";
    1114             281 :   o->newline() << "rc = -EINVAL;";
    1115             281 :   o->newline(-1) << "}";
    1116                 : 
    1117             281 :   o->newline(-1) << "}";
    1118             281 :   o->newline() << "up_read (& uts_sem);";
    1119             281 :   o->newline() << "if (rc) goto out;";
    1120                 : 
    1121             281 :   o->newline() << "(void) probe_point;";
    1122             281 :   o->newline() << "(void) i;";
    1123             281 :   o->newline() << "(void) j;";
    1124             281 :   o->newline() << "atomic_set (&session_state, STAP_SESSION_STARTING);";
    1125                 :   // This signals any other probes that may be invoked in the next little
    1126                 :   // while to abort right away.  Currently running probes are allowed to
    1127                 :   // terminate.  These may set STAP_SESSION_ERROR!
    1128                 : 
    1129                 :   // per-cpu context
    1130             281 :   o->newline() << "if (sizeof (struct context) <= 131072)";
    1131             281 :   o->newline(1) << "contexts = alloc_percpu (struct context);";
    1132             281 :   o->newline(-1) << "if (contexts == NULL) {";
    1133             281 :   o->newline(1) << "_stp_error (\"percpu context (size %lu) allocation failed\", sizeof (struct context));";
    1134             281 :   o->newline() << "rc = -ENOMEM;";
    1135             281 :   o->newline() << "goto out;";
    1136             281 :   o->newline(-1) << "}";
    1137                 :   
    1138             712 :   for (unsigned i=0; i<session->globals.size(); i++)
    1139                 :     {
    1140             431 :       vardecl* v = session->globals[i];      
    1141             431 :       if (v->index_types.size() > 0)
    1142             274 :         o->newline() << getmap (v).init();
    1143                 :       else
    1144             157 :         o->newline() << getvar (v).init();
    1145                 :       // NB: in case of failure of allocation, "rc" will be set to non-zero.
    1146                 :       // Allocation can in general continue.
    1147                 : 
    1148             431 :       o->newline() << "if (rc) {";
    1149             431 :       o->newline(1) << "_stp_error (\"global variable " << v->name << " allocation failed\");";
    1150             431 :       o->newline() << "goto out;";
    1151             431 :       o->newline(-1) << "}";
    1152                 : 
    1153             431 :       o->newline() << "rwlock_init (& global.s_" << c_varname (v->name) << "_lock);";
    1154                 :     }
    1155                 : 
    1156                 :   // initialize each Stat used for timing information 
    1157             281 :   o->newline() << "#ifdef STP_TIMING";
    1158             281 :   set<string> basest_names;
    1159            9535 :   for (unsigned i=0; i<session->probes.size(); i++)
    1160                 :     {
    1161            9254 :       string nm = session->probes[i]->basest()->name;
    1162            9254 :       if (basest_names.find(nm) == basest_names.end())
    1163                 :         {
    1164             682 :           o->newline() << "time_" << nm << " = _stp_stat_init (HIST_NONE);";
    1165                 :           // NB: we don't check for null return here, but instead at
    1166                 :           // passage to probe handlers and at final printing.
    1167             682 :           basest_names.insert (nm);
    1168                 :         }
    1169                 :     }
    1170             281 :   o->newline() << "#endif";
    1171                 : 
    1172                 :   // Print a message to the kernel log about this module.  This is
    1173                 :   // intended to help debug problems with systemtap modules.
    1174                 : 
    1175                 :   o->newline() << "_stp_print_kernel_info("
    1176                 :                << "\"" << VERSION 
    1177                 :                << "/" << dwfl_version (NULL) << "\""
    1178                 :                << ", (num_online_cpus() * sizeof(struct context))"
    1179                 :                << ", " << session->probes.size()
    1180             281 :                << ");";
    1181                 : 
    1182                 :   // Run all probe registrations.  This actually runs begin probes.
    1183                 : 
    1184             656 :   for (unsigned i=0; i<g.size(); i++)
    1185                 :     {
    1186             375 :       g[i]->emit_module_init (*session);
    1187                 :       // NB: this gives O(N**2) amount of code, but luckily there
    1188                 :       // are only seven or eight derived_probe_groups, so it's ok.
    1189             375 :       o->newline() << "if (rc) {";
    1190             375 :       o->newline(1) << "_stp_error (\"probe %s registration error (rc %d)\", probe_point, rc);";
    1191                 :       // NB: we need to be in the error state so timers can shutdown cleanly,
    1192                 :       // and so end probes don't run.  OTOH, error probes can run.
    1193             375 :       o->newline() << "atomic_set (&session_state, STAP_SESSION_ERROR);";
    1194             375 :       if (i>0)
    1195             217 :         for (int j=i-1; j>=0; j--)
    1196             122 :           g[j]->emit_module_exit (*session);
    1197             375 :       o->newline() << "goto out;";
    1198             375 :       o->newline(-1) << "}";
    1199                 :     }
    1200                 : 
    1201                 :   // All registrations were successful.  Consider the system started.
    1202             281 :   o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_STARTING)";
    1203                 :   // NB: only other valid state value is ERROR, in which case we don't 
    1204             281 :   o->newline(1) << "atomic_set (&session_state, STAP_SESSION_RUNNING);";
    1205             281 :   o->newline(-1) << "return 0;";
    1206                 : 
    1207                 :   // Error handling path; by now all partially registered probe groups
    1208                 :   // have been unregistered.
    1209             281 :   o->newline(-1) << "out:";
    1210             281 :   o->indent(1);
    1211                 : 
    1212                 :   // If any registrations failed, we will need to deregister the globals,
    1213                 :   // as this is our only chance.
    1214             712 :   for (unsigned i=0; i<session->globals.size(); i++)
    1215                 :     {
    1216             431 :       vardecl* v = session->globals[i];      
    1217             431 :       if (v->index_types.size() > 0)
    1218             274 :         o->newline() << getmap (v).fini();
    1219                 :       else
    1220             157 :         o->newline() << getvar (v).fini();
    1221                 :     }
    1222                 : 
    1223             281 :   o->newline() << "return rc;";
    1224             281 :   o->newline(-1) << "}\n";
    1225             281 : }
    1226                 : 
    1227                 : 
    1228                 : void
    1229             281 : c_unparser::emit_module_exit ()
    1230                 : {
    1231             281 :   o->newline() << "void systemtap_module_exit (void) {";
    1232                 :   // rc?
    1233             281 :   o->newline(1) << "int holdon;";
    1234             281 :   o->newline() << "int i=0, j=0;"; // for derived_probe_group use
    1235                 : 
    1236             281 :   o->newline() << "(void) i;";
    1237             281 :   o->newline() << "(void) j;";
    1238                 :   // If we aborted startup, then everything has been cleaned up already, and
    1239                 :   // module_exit shouldn't even have been called.  But since it might be, let's
    1240                 :   // beat a hasty retreat to avoid double uninitialization.
    1241             281 :   o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_STARTING)";
    1242             281 :   o->newline(1) << "return;";
    1243             281 :   o->indent(-1);
    1244                 :   
    1245             281 :   o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_RUNNING)";
    1246                 :   // NB: only other valid state value is ERROR, in which case we don't 
    1247             281 :   o->newline(1) << "atomic_set (&session_state, STAP_SESSION_STOPPING);";
    1248             281 :   o->indent(-1);
    1249                 :   // This signals any other probes that may be invoked in the next little
    1250                 :   // while to abort right away.  Currently running probes are allowed to
    1251                 :   // terminate.  These may set STAP_SESSION_ERROR!
    1252                 : 
    1253                 :   // NB: systemtap_module_exit is assumed to be called from ordinary
    1254                 :   // user context, say during module unload.  Among other things, this
    1255                 :   // means we can sleep a while.
    1256             281 :   o->newline() << "do {";
    1257             281 :   o->newline(1) << "int i;";
    1258             281 :   o->newline() << "holdon = 0;";
    1259             281 :   o->newline() << "for (i=0; i < NR_CPUS; i++)";
    1260                 :   o->newline(1) << "if (cpu_possible (i) && " 
    1261                 :                 << "atomic_read (& ((struct context *)per_cpu_ptr(contexts, i))->busy)) "
    1262             281 :                 << "holdon = 1;";
    1263             281 :   o->newline () << "schedule ();";
    1264             281 :   o->newline(-2) << "} while (holdon);";
    1265                 : 
    1266                 :   // XXX: might like to have an escape hatch, in case some probe is
    1267                 :   // genuinely stuck somehow
    1268                 : 
    1269                 :   // Notice we're processing the derived_probe_group list in reverse
    1270                 :   // order.  This ensures that probes get unregistered in reverse
    1271                 :   // order of the way they were registered.
    1272             281 :   vector<derived_probe_group*> g = all_session_groups (*session);
    1273             656 :   for (vector<derived_probe_group*>::reverse_iterator i = g.rbegin();
    1274                 :        i != g.rend(); i++)
    1275             375 :     (*i)->emit_module_exit (*session); // NB: runs "end" probes
    1276                 : 
    1277             712 :   for (unsigned i=0; i<session->globals.size(); i++)
    1278                 :     {
    1279             431 :       vardecl* v = session->globals[i];      
    1280             431 :       if (v->index_types.size() > 0)
    1281             274 :         o->newline() << getmap (v).fini();
    1282                 :       else
    1283             157 :         o->newline() << getvar (v).fini();
    1284                 :     }
    1285                 : 
    1286             281 :   o->newline() << "free_percpu (contexts);";
    1287                 : 
    1288                 :   // print probe timing statistics
    1289                 :   {
    1290             281 :     o->newline() << "#ifdef STP_TIMING";
    1291             281 :     o->newline() << "{";
    1292             281 :     o->indent(1);
    1293             281 :     set<string> basest_names;
    1294            9535 :     for (unsigned i=0; i<session->probes.size(); i++)
    1295                 :       {
    1296            9254 :         probe* p = session->probes[i]->basest();
    1297            9254 :         string nm = p->name;
    1298            9254 :         if (basest_names.find(nm) == basest_names.end())
    1299                 :           {
    1300             682 :             basest_names.insert (nm);
    1301                 :             // NB: check for null stat object
    1302             682 :             o->newline() << "if (likely (time_" << p->name << ")) {";
    1303                 :             o->newline(1) << "const char *probe_point = " 
    1304                 :                          << lex_cast_qstring (* p->locations[0])
    1305                 :                          << (p->locations.size() > 1 ? "\"+\"" : "")
    1306                 :                          << (p->locations.size() > 1 ? lex_cast_qstring(p->locations.size()-1) : "")
    1307             682 :                          << ";";
    1308                 :             o->newline() << "const char *decl_location = "
    1309                 :                          << lex_cast_qstring (p->tok->location)
    1310             682 :                          << ";";
    1311                 :             o->newline() << "struct stat_data *stats = _stp_stat_get (time_"
    1312                 :                          << p->name
    1313             682 :                          << ", 0);";
    1314             682 :             o->newline() << "const char *error;";
    1315             682 :             o->newline() << "if (stats->count) {";
    1316             682 :             o->newline(1) << "int64_t avg = _stp_div64 (&error, stats->sum, stats->count);";
    1317             682 :             o->newline() << "_stp_printf (\"probe %s (%s), hits: %lld, cycles: %lldmin/%lldavg/%lldmax\\n\",";
    1318             682 :             o->newline() << "probe_point, decl_location, (long long) stats->count, (long long) stats->min, (long long) avg, (long long) stats->max);";
    1319             682 :             o->newline(-1) << "}";
    1320             682 :             o->newline() << "_stp_stat_del (time_" << p->name << ");";
    1321             682 :             o->newline(-1) << "}";
    1322                 :           }
    1323                 :       }
    1324             281 :     o->newline() << "_stp_print_flush();";
    1325             281 :     o->newline(-1) << "}";
    1326             281 :     o->newline() << "#endif";
    1327                 :   }
    1328                 : 
    1329                 :   // print final error/reentrancy counts if non-zero
    1330                 :   o->newline() << "if (atomic_read (& skipped_count) || "
    1331             281 :                << "atomic_read (& error_count)) {";
    1332                 :   o->newline(1) << "_stp_warn (\"Number of errors: %d, "
    1333                 :                 << "skipped probes: %d\\n\", "
    1334                 :                 << "(int) atomic_read (& error_count), "
    1335             281 :                 << "(int) atomic_read (& skipped_count));";
    1336             281 :   o->newline() << "_stp_print_flush();";
    1337             281 :   o->newline(-1) << "}";
    1338             281 :   o->newline(-1) << "}\n";
    1339             281 : }
    1340                 : 
    1341                 : 
    1342                 : void
    1343            1242 : c_unparser::emit_function (functiondecl* v)
    1344                 : {
    1345                 :   o->newline() << "void function_" << c_varname (v->name)
    1346            1242 :             << " (struct context* __restrict__ c) {";
    1347            1242 :   o->indent(1);
    1348            1242 :   this->current_probe = 0;
    1349            1242 :   this->current_function = v;
    1350            1242 :   this->tmpvar_counter = 0;
    1351                 : 
    1352                 :   o->newline()
    1353                 :     << "struct function_" << c_varname (v->name) << "_locals * "
    1354            2484 :     << " __restrict__ l =";
    1355                 :   o->newline(1)
    1356                 :     << "& c->locals[c->nesting+1].function_" << c_varname (v->name) // NB: nesting+1
    1357            2484 :     << ";";
    1358            1242 :   o->newline(-1) << "(void) l;"; // make sure "l" is marked used
    1359            1242 :   o->newline() << "#define CONTEXT c";
    1360            1242 :   o->newline() << "#define THIS l";
    1361            1242 :   o->newline() << "if (0) goto out;"; // make sure out: is marked used
    1362                 : 
    1363                 :   // check/increment nesting level
    1364            1242 :   o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {";
    1365            1242 :   o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";";
    1366            1242 :   o->newline() << "return;";
    1367            1242 :   o->newline(-1) << "} else {";
    1368            1242 :   o->newline(1) << "c->nesting ++;";
    1369            1242 :   o->newline(-1) << "}";
    1370                 : 
    1371                 :   // initialize locals
    1372                 :   // XXX: optimization: use memset instead
    1373            2638 :   for (unsigned i=0; i<v->locals.size(); i++)
    1374                 :     {
    1375              77 :       if (v->locals[i]->index_types.size() > 0) // array?
    1376                 :         throw semantic_error ("array locals not supported, missing global declaration?", 
    1377               0 :                               v->locals[i]->tok);
    1378                 : 
    1379              77 :       o->newline() << getvar (v->locals[i]).init();
    1380                 :     }
    1381                 : 
    1382                 :   // initialize return value, if any
    1383            1242 :   if (v->type != pe_unknown)
    1384                 :     {
    1385            1028 :       var retvalue = var(true, v->type, "__retvalue");
    1386            2056 :       o->newline() << retvalue.init();
    1387                 :     }
    1388                 : 
    1389            1242 :   o->newline() << "#define return goto out"; // redirect embedded-C return
    1390            1242 :   this->probe_or_function_needs_deref_fault_handler = false;
    1391            1242 :   v->body->visit (this);
    1392            1242 :   o->newline() << "#undef return";
    1393                 : 
    1394            1242 :   this->current_function = 0;
    1395                 : 
    1396            1242 :   o->newline(-1) << "out:";
    1397            1242 :   o->newline(1) << ";";
    1398                 : 
    1399                 :   // Function prologue: this is why we redirect the "return" above.
    1400                 :   // Decrement nesting level.
    1401            1242 :   o->newline() << "c->nesting --;";
    1402                 :   // Reset last_error to NULL if it was set to "" by script-level return()
    1403            1242 :   o->newline() << "if (c->last_error && ! c->last_error[0])";
    1404            1242 :   o->newline(1) << "c->last_error = 0;";
    1405            1242 :   o->indent(-1);
    1406                 : 
    1407            1242 :   if (this->probe_or_function_needs_deref_fault_handler) {
    1408                 :     // Emit this handler only if the body included a
    1409                 :     // print/printf/etc. using a string or memory buffer!
    1410               0 :     o->newline(1) << "return;";
    1411               0 :     o->newline() << "CATCH_DEREF_FAULT ();";
    1412               0 :     o->newline() << "goto out;";
    1413               0 :     o->indent(-1);
    1414                 :   }
    1415                 : 
    1416            1242 :   o->newline() << "#undef CONTEXT";
    1417            1242 :   o->newline() << "#undef THIS";
    1418            1242 :   o->newline(-1) << "}\n";
    1419            1242 : }
    1420                 : 
    1421                 : 
    1422                 : #define DUPMETHOD_CALL 0
    1423                 : #define DUPMETHOD_ALIAS 0
    1424                 : #define DUPMETHOD_RENAME 1
    1425                 : 
    1426                 : void
    1427            9255 : c_unparser::emit_probe (derived_probe* v)
    1428                 : {
    1429            9255 :   this->current_function = 0;
    1430            9255 :   this->current_probe = v;
    1431            9255 :   this->tmpvar_counter = 0;
    1432                 : 
    1433                 :   // If we about to emit a probe that is exactly the same as another
    1434                 :   // probe previously emitted, make the second probe just call the
    1435                 :   // first one.
    1436                 :   //
    1437                 :   // Notice we're using the probe body itself instead of the emitted C
    1438                 :   // probe body to compare probes.  We need to do this because the
    1439                 :   // emitted C probe body has stuff in it like:
    1440                 :   //   c->last_stmt = "identifier 'printf' at foo.stp:<line>:<column>";
    1441                 :   //
    1442                 :   // which would make comparisons impossible.
    1443                 :   //
    1444                 :   // --------------------------------------------------------------------------
    1445                 :   // NB: see also c_unparser:emit_common_header(), which deliberately but sadly
    1446                 :   // duplicates this calculation.
    1447                 :   // --------------------------------------------------------------------------
    1448                 :   //
    1449            9255 :   ostringstream oss;
    1450                 : 
    1451                 :   // NB: statp is just for avoiding designation as duplicate.  It need not be C.
    1452                 :   // NB: This code *could* be enclosed in an "if (session->timing)".  That would
    1453                 :   // recognize more duplicate probe handlers, but then the generated code could
    1454                 :   // be very different with or without -t.
    1455            9255 :   oss << "c->statp = & time_" << v->basest()->name << ";" << endl; 
    1456                 : 
    1457            9255 :   v->body->print(oss);
    1458                 : 
    1459                 :   // Since the generated C changes based on whether or not the probe
    1460                 :   // needs locks around global variables, this needs to be reflected
    1461                 :   // here.  We don't want to treat as duplicate the handlers of
    1462                 :   // begin/end and normal probes that differ only in need_global_locks.
    1463            9255 :   oss << "# needs_global_locks: " << v->needs_global_locks () << endl;
    1464                 : 
    1465                 :   // If an identical probe has already been emitted, just call that
    1466                 :   // one.
    1467            9255 :   if (probe_contents.count(oss.str()) != 0)
    1468                 :     {
    1469            7139 :       string dupe = probe_contents[oss.str()];
    1470                 : 
    1471                 :       // NB: Elision of context variable structs is a separate
    1472                 :       // operation which has already taken place by now.
    1473            7139 :       if (session->verbose > 1)
    1474               0 :         clog << v->name << " elided, duplicates " << dupe << endl;
    1475                 : 
    1476                 : #if DUPMETHOD_CALL
    1477                 :       // This one emits a direct call to the first copy.
    1478                 :       o->newline();
    1479                 :       o->newline() << "static void " << v->name << " (struct context * __restrict__ c) ";
    1480                 :       o->newline() << "{ " << dupe << " (c); }";
    1481                 : #elif DUPMETHOD_ALIAS
    1482                 :       // This one defines a function alias, arranging gcc to emit
    1483                 :       // several equivalent symbols for the same function body.
    1484                 :       // For some reason, on gcc 4.1, this is twice as slow as
    1485                 :       // the CALL option.
    1486                 :       o->newline();
    1487                 :       o->newline() << "static void " << v->name << " (struct context * __restrict__ c) ";
    1488                 :       o->line() << "__attribute__ ((alias (\"" << dupe << "\")));";
    1489                 : #elif DUPMETHOD_RENAME
    1490                 :       // This one is sneaky.  It emits nothing for duplicate probe
    1491                 :       // handlers.  It instead redirects subsequent references to the
    1492                 :       // probe handler function to the first copy, *by name*.
    1493            7139 :       v->name = dupe;
    1494                 : #else
    1495                 : #error "Unknown duplicate elimination method"
    1496                 : #endif
    1497                 :     }
    1498                 :   else // This probe is unique.  Remember it and output it.
    1499                 :     {
    1500            2116 :       this->probe_or_function_needs_deref_fault_handler = false;
    1501                 : 
    1502            2116 :       o->newline();
    1503            2116 :       o->newline() << "#ifdef STP_TIMING";
    1504            2116 :       o->newline() << "static __cacheline_aligned Stat " << "time_" << v->basest()->name << ";";
    1505            2116 :       o->newline() << "#endif";
    1506            2116 :       o->newline();
    1507            2116 :       o->newline() << "static void " << v->name << " (struct context * __restrict__ c) ";
    1508            2116 :       o->line () << "{";
    1509            2116 :       o->indent (1);
    1510                 : 
    1511            2116 :       probe_contents[oss.str()] = v->name;
    1512                 : 
    1513                 :       // initialize frame pointer
    1514            2116 :       o->newline() << "struct " << v->name << "_locals * __restrict__ l =";
    1515            2116 :       o->newline(1) << "& c->locals[0]." << v->name << ";";
    1516            2116 :       o->newline(-1) << "(void) l;"; // make sure "l" is marked used
    1517                 :       
    1518            2116 :       o->newline() << "#ifdef STP_TIMING";
    1519            2116 :       o->newline() << "c->statp = & time_" << v->basest()->name << ";";
    1520            2116 :       o->newline() << "#endif";
    1521                 : 
    1522                 :       // emit all read/write locks for global variables
    1523            2116 :       varuse_collecting_visitor vut;
    1524            2116 :       if (v->needs_global_locks ())
    1525                 :         {
    1526            1714 :           v->body->visit (& vut);
    1527            1714 :           emit_locks (vut);
    1528                 :         }
    1529                 : 
    1530                 :       // initialize locals
    1531            6704 :       for (unsigned j=0; j<v->locals.size(); j++)
    1532                 :         {
    1533            4589 :           if (v->locals[j]->index_types.size() > 0) // array?
    1534                 :             throw semantic_error ("array locals not supported, missing global declaration?", 
    1535               1 :                                   v->locals[j]->tok);
    1536            4588 :           else if (v->locals[j]->type == pe_long)
    1537                 :             o->newline() << "l->" << c_varname (v->locals[j]->name)
    1538            1069 :                          << " = 0;";
    1539            3519 :           else if (v->locals[j]->type == pe_string)
    1540                 :             o->newline() << "l->" << c_varname (v->locals[j]->name)
    1541            3519 :                          << "[0] = '\\0';";
    1542                 :           else
    1543                 :             throw semantic_error ("unsupported local variable type",
    1544               0 :                                   v->locals[j]->tok);
    1545                 :         }
    1546                 : 
    1547            2115 :       v->initialize_probe_context_vars (o);
    1548                 : 
    1549            2115 :       v->body->visit (this);
    1550                 : 
    1551            2115 :       o->newline(-1) << "out:";
    1552                 :       // NB: no need to uninitialize locals, except if arrays/stats can
    1553                 :       // someday be local 
    1554                 : 
    1555                 :       // XXX: do this flush only if the body included a
    1556                 :       // print/printf/etc. routine!
    1557            2115 :       o->newline(1) << "_stp_print_flush();";
    1558                 : 
    1559            2115 :       if (v->needs_global_locks ())
    1560            1714 :         emit_unlocks (vut);
    1561                 : 
    1562            2115 :       if (this->probe_or_function_needs_deref_fault_handler) {
    1563                 :         // Emit this handler only if the body included a
    1564                 :         // print/printf/etc. using a string or memory buffer!
    1565               4 :         o->newline() << "return;";
    1566               4 :         o->newline() << "CATCH_DEREF_FAULT ();";
    1567               4 :         o->newline() << "goto out;";
    1568                 :       }
    1569                 : 
    1570            2115 :       o->newline(-1) << "}\n";
    1571                 :     }
    1572                 : 
    1573                 :   
    1574            9255 :   this->current_probe = 0;
    1575            9254 : }
    1576                 : 
    1577                 : 
    1578                 : void 
    1579            1714 : c_unparser::emit_locks(const varuse_collecting_visitor& vut)
    1580                 : {
    1581            1714 :   o->newline() << "{";
    1582            1714 :   o->newline(1) << "unsigned numtrylock = 0;";
    1583            1714 :   o->newline() << "(void) numtrylock;";
    1584                 : 
    1585            1714 :   string last_locked_var;
    1586           10671 :   for (unsigned i = 0; i < session->globals.size(); i++)
    1587                 :     {
    1588            7650 :       vardecl* v = session->globals[i];
    1589            7650 :       bool read_p = vut.read.find(v) != vut.read.end();
    1590            7650 :       bool write_p = vut.written.find(v) != vut.written.end();
    1591            7650 :       if (!read_p && !write_p) continue;
    1592                 : 
    1593            1837 :       if (v->type == pe_stats) // read and write locks are flipped
    1594                 :         // Specifically, a "<<<" to a stats object is considered a
    1595                 :         // "shared-lock" operation, since it's implicitly done
    1596                 :         // per-cpu.  But a "@op(x)" extraction is an "exclusive-lock"
    1597                 :         // one, as is a (sorted or unsorted) foreach, so those cases
    1598                 :         // are excluded by the w & !r condition below.
    1599                 :         {
    1600              34 :           if (write_p && !read_p) { read_p = true; write_p = false; }
    1601               8 :           else if (read_p && !write_p) { read_p = false; write_p = true; }
    1602                 :         }
    1603                 : 
    1604                 :       // We don't need to read lock "read-mostly" global variables.  A
    1605                 :       // "read-mostly" global variable is only written to within
    1606                 :       // probes that don't need global variable locking (such as
    1607                 :       // begin/end probes).  If vcv_needs_global_locks doesn't mark
    1608                 :       // the global as written to, then we don't have to lock it
    1609                 :       // here to read it safely.
    1610            1837 :       if (read_p && !write_p)
    1611                 :         {
    1612             585 :           if (vcv_needs_global_locks.written.find(v)
    1613                 :               == vcv_needs_global_locks.written.end())
    1614             530 :             continue;
    1615                 :         }
    1616                 : 
    1617                 :       string lockcall = 
    1618                 :         string (write_p ? "write" : "read") +
    1619            1307 :         "_trylock (& global.s_" + v->name + "_lock)";
    1620                 : 
    1621                 :       o->newline() << "while (! " << lockcall
    1622            2614 :                    << "&& (++numtrylock < MAXTRYLOCK))";
    1623            1307 :       o->newline(1) << "ndelay (TRYLOCKDELAY);";
    1624            1307 :       o->newline(-1) << "if (unlikely (numtrylock >= MAXTRYLOCK)) {";
    1625            1307 :       o->newline(1) << "atomic_inc (& skipped_count);";
    1626                 :       // The following works even if i==0.  Note that using
    1627                 :       // globals[i-1]->name is wrong since that global may not have
    1628                 :       // been lockworthy by this probe.
    1629            1307 :       o->newline() << "goto unlock_" << last_locked_var << ";";
    1630            1307 :       o->newline(-1) << "}";
    1631                 : 
    1632            1307 :       last_locked_var = v->name;
    1633                 :     }
    1634                 : 
    1635            1714 :   o->newline() << "if (0) goto unlock_;";
    1636                 : 
    1637            1714 :   o->newline(-1) << "}";
    1638            1714 : }
    1639                 : 
    1640                 : 
    1641                 : void 
    1642            1714 : c_unparser::emit_unlocks(const varuse_collecting_visitor& vut)
    1643                 : {
    1644            1714 :   unsigned numvars = 0;
    1645                 : 
    1646            1714 :   if (session->verbose>1)
    1647               0 :     clog << current_probe->name << " locks ";
    1648                 : 
    1649            9364 :   for (int i = session->globals.size()-1; i>=0; i--) // in reverse order!
    1650                 :     {
    1651            7650 :       vardecl* v = session->globals[i];
    1652            7650 :       bool read_p = vut.read.find(v) != vut.read.end();
    1653            7650 :       bool write_p = vut.written.find(v) != vut.written.end();
    1654            7650 :       if (!read_p && !write_p) continue;
    1655                 : 
    1656                 :       // Duplicate lock flipping logic from above
    1657            1837 :       if (v->type == pe_stats)
    1658                 :         {
    1659              34 :           if (write_p && !read_p) { read_p = true; write_p = false; }
    1660               8 :           else if (read_p && !write_p) { read_p = false; write_p = true; }
    1661                 :         }
    1662                 : 
    1663                 :       // Duplicate "read-mostly" global variable logic from above.
    1664            1837 :       if (read_p && !write_p)
    1665                 :         {
    1666             585 :           if (vcv_needs_global_locks.written.find(v)
    1667                 :               == vcv_needs_global_locks.written.end())
    1668             530 :             continue;
    1669                 :         }
    1670                 : 
    1671            1307 :       numvars ++;
    1672            1307 :       o->newline(-1) << "unlock_" << v->name << ":";
    1673            1307 :       o->indent(1);
    1674                 : 
    1675            1307 :       if (session->verbose>1)
    1676                 :         clog << v->name << "[" << (read_p ? "r" : "")
    1677               0 :              << (write_p ? "w" : "")  << "] ";
    1678                 : 
    1679            1307 :       if (write_p) // emit write lock
    1680            1252 :         o->newline() << "write_unlock (& global.s_" << v->name << "_lock);";
    1681                 :       else // (read_p && !write_p) : emit read lock
    1682              55 :         o->newline() << "read_unlock (& global.s_" << v->name << "_lock);";
    1683                 : 
    1684                 :       // fall through to next variable; thus the reverse ordering
    1685                 :     }
    1686                 :   
    1687                 :   // emit plain "unlock" label, used if the very first lock failed.
    1688            1714 :   o->newline(-1) << "unlock_: ;";
    1689            1714 :   o->indent(1);
    1690                 : 
    1691            1714 :   if (numvars) // is there a chance that any lock attempt failed?
    1692                 :     {
    1693             617 :       o->newline() << "if (atomic_read (& skipped_count) > MAXSKIPPED) {";
    1694                 :       // XXX: In this known non-reentrant context, we could print a more
    1695                 :       // informative error.
    1696             617 :       o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
    1697             617 :       o->newline() << "_stp_exit();";
    1698             617 :       o->newline(-1) << "}";
    1699                 : 
    1700             617 :       if (session->verbose>1)
    1701               0 :         clog << endl;
    1702                 :     }
    1703            1097 :   else if (session->verbose>1)
    1704               0 :     clog << "nothing" << endl;
    1705            1714 : }
    1706                 : 
    1707                 : 
    1708                 : void 
    1709                 : c_unparser::collect_map_index_types(vector<vardecl *> const & vars,
    1710           10779 :                                     set< pair<vector<exp_type>, exp_type> > & types)
    1711                 : {
    1712           18484 :   for (unsigned i = 0; i < vars.size(); ++i)
    1713                 :     {
    1714            7705 :       vardecl *v = vars[i];
    1715            7705 :       if (v->arity > 0)
    1716                 :         {
    1717             275 :           types.insert(make_pair(v->index_types, v->type));
    1718                 :         }
    1719                 :     }
    1720           10779 : }
    1721                 : 
    1722                 : string
    1723             120 : mapvar::value_typename(exp_type e)
    1724                 : {
    1725             120 :   switch (e)
    1726                 :     {
    1727                 :     case pe_long:
    1728              58 :       return "INT64";
    1729                 :     case pe_string:
    1730              24 :       return "STRING";
    1731                 :     case pe_stats:
    1732              38 :       return "STAT";
    1733                 :     default:
    1734               0 :       throw semantic_error("array type is neither string nor long");
    1735                 :     }
    1736                 :   return "";
    1737                 : }
    1738                 : 
    1739                 : string
    1740             172 : mapvar::key_typename(exp_type e)
    1741                 : {
    1742             172 :   switch (e)
    1743                 :     {
    1744                 :     case pe_long:
    1745             123 :       return "INT64";
    1746                 :     case pe_string:
    1747              49 :       return "STRING";
    1748                 :     default:
    1749               0 :       throw semantic_error("array key is neither string nor long");
    1750                 :     }         
    1751                 :   return "";
    1752                 : }
    1753                 : 
    1754                 : string
    1755               0 : mapvar::shortname(exp_type e)
    1756                 : {
    1757               0 :   switch (e)
    1758                 :     {
    1759                 :     case pe_long:
    1760               0 :       return "i";
    1761                 :     case pe_string:
    1762               0 :       return "s";
    1763                 :     default:
    1764               0 :       throw semantic_error("array type is neither string nor long");
    1765                 :     }         
    1766                 :   return "";
    1767                 : }
    1768                 : 
    1769                 : 
    1770                 : void
    1771             282 : c_unparser::emit_map_type_instantiations ()
    1772                 : {
    1773             282 :   set< pair<vector<exp_type>, exp_type> > types;
    1774                 :   
    1775             282 :   collect_map_index_types(session->globals, types);
    1776                 : 
    1777            9537 :   for (unsigned i = 0; i < session->probes.size(); ++i)
    1778            9255 :     collect_map_index_types(session->probes[i]->locals, types);
    1779                 : 
    1780            1524 :   for (unsigned i = 0; i < session->functions.size(); ++i)
    1781            1242 :     collect_map_index_types(session->functions[i]->locals, types);
    1782                 : 
    1783             282 :   if (!types.empty())
    1784              66 :     o->newline() << "#include \"alloc.c\"";
    1785                 : 
    1786             383 :   for (set< pair<vector<exp_type>, exp_type> >::const_iterator i = types.begin();
    1787                 :        i != types.end(); ++i)
    1788                 :     {
    1789             101 :       o->newline() << "#define VALUE_TYPE " << mapvar::value_typename(i->second);
    1790             248 :       for (unsigned j = 0; j < i->first.size(); ++j)
    1791                 :         {
    1792             147 :           string ktype = mapvar::key_typename(i->first.at(j));
    1793             147 :           o->newline() << "#define KEY" << (j+1) << "_TYPE " << ktype;
    1794                 :         }
    1795             101 :       if (i->second == pe_stats)
    1796              19 :         o->newline() << "#include \"pmap-gen.c\"";
    1797                 :       else
    1798              82 :         o->newline() << "#include \"map-gen.c\"";
    1799             101 :       o->newline() << "#undef VALUE_TYPE";
    1800             248 :       for (unsigned j = 0; j < i->first.size(); ++j)
    1801                 :         {
    1802             147 :           o->newline() << "#undef KEY" << (j+1) << "_TYPE";
    1803                 :         }      
    1804                 : 
    1805                 :       /* FIXME
    1806                 :        * For pmaps, we also need to include map-gen.c, because we might be accessing
    1807                 :        * the aggregated map.  The better way to handle this is for pmap-gen.c to make
    1808                 :        * this include, but that's impossible with the way they are set up now.
    1809                 :        */
    1810             101 :       if (i->second == pe_stats)
    1811                 :         {
    1812              19 :           o->newline() << "#define VALUE_TYPE " << mapvar::value_typename(i->second);
    1813              44 :           for (unsigned j = 0; j < i->first.size(); ++j)
    1814                 :             {
    1815              25 :               string ktype = mapvar::key_typename(i->first.at(j));
    1816              25 :               o->newline() << "#define KEY" << (j+1) << "_TYPE " << ktype;
    1817                 :             }
    1818              19 :           o->newline() << "#include \"map-gen.c\"";
    1819              19 :           o->newline() << "#undef VALUE_TYPE";
    1820              44 :           for (unsigned j = 0; j < i->first.size(); ++j)
    1821                 :             {
    1822              25 :               o->newline() << "#undef KEY" << (j+1) << "_TYPE";
    1823                 :             }      
    1824                 :         }
    1825                 :     }
    1826                 : 
    1827             282 :   if (!types.empty())
    1828              66 :     o->newline() << "#include \"map.c\"";
    1829                 : 
    1830             282 : };
    1831                 : 
    1832                 : 
    1833                 : string
    1834           26638 : c_unparser::c_typename (exp_type e)
    1835                 : {
    1836           26638 :   switch (e)
    1837                 :     {
    1838           11600 :     case pe_long: return string("int64_t");
    1839           14996 :     case pe_string: return string("string_t"); 
    1840              42 :     case pe_stats: return string("Stat");
    1841                 :     case pe_unknown: 
    1842                 :     default:
    1843               0 :       throw semantic_error ("cannot expand unknown type");
    1844                 :     }
    1845                 : }
    1846                 : 
    1847                 : 
    1848                 : string
    1849           59611 : c_unparser::c_varname (const string& e)
    1850                 : {
    1851                 :   // XXX: safeify, uniquefy, given name
    1852           59611 :   return e;
    1853                 : }
    1854                 : 
    1855                 : 
    1856                 : string
    1857            5023 : c_unparser::c_expression (expression *e)
    1858                 : {
    1859                 :   // We want to evaluate expression 'e' and return its value as a
    1860                 :   // string.  In the case of expressions that are just numeric
    1861                 :   // constants, if we just print the value into a string, it won't
    1862                 :   // have the same value as being visited by c_unparser.  For
    1863                 :   // instance, a numeric constant evaluated using print() would return
    1864                 :   // "5", while c_unparser::visit_literal_number() would
    1865                 :   // return "((int64_t)5LL)".  String constants evaluated using
    1866                 :   // print() would just return the string, while
    1867                 :   // c_unparser::visit_literal_string() would return the string with
    1868                 :   // escaped double quote characters.  So, we need to "visit" the
    1869                 :   // expression.
    1870                 : 
    1871                 :   // However, we have to be careful of side effects.  Currently this
    1872                 :   // code is only being used for evaluating literal numbers and
    1873                 :   // strings, which currently have no side effects.  Until needed
    1874                 :   // otherwise, limit the use of this function to literal numbers and
    1875                 :   // strings.
    1876            5023 :   if (e->tok->type != tok_number && e->tok->type != tok_string)
    1877               0 :     throw semantic_error("unsupported c_expression token type");
    1878                 : 
    1879                 :   // Create a fake output stream so we can grab the string output.
    1880            5023 :   ostringstream oss;
    1881            5023 :   translator_output tmp_o(oss);
    1882                 : 
    1883                 :   // Temporarily swap out the real translator_output stream with our
    1884                 :   // fake one.
    1885            5023 :   translator_output *saved_o = o;
    1886            5023 :   o = &tmp_o;
    1887                 : 
    1888                 :   // Visit the expression then restore the original output stream
    1889            5023 :   e->visit (this);
    1890            5023 :   o = saved_o;
    1891                 : 
    1892            5023 :   return (oss.str());
    1893                 : }
    1894                 : 
    1895                 : 
    1896                 : void 
    1897            1309 : c_unparser::c_assign (var& lvalue, const string& rvalue, const token *tok)
    1898                 : {  
    1899            1309 :   switch (lvalue.type())
    1900                 :     {
    1901                 :     case pe_string:
    1902             413 :       c_strcpy(lvalue.value(), rvalue);
    1903             413 :       break;
    1904                 :     case pe_long:
    1905             896 :       o->newline() << lvalue << " = " << rvalue << ";";
    1906             896 :       break;
    1907                 :     default:
    1908               0 :       throw semantic_error ("unknown lvalue type in assignment", tok);
    1909                 :     }
    1910            1309 : }
    1911                 : 
    1912                 : void
    1913                 : c_unparser::c_assign (const string& lvalue, expression* rvalue,
    1914           16855 :                       const string& msg)
    1915                 : {
    1916           16855 :   if (rvalue->type == pe_long)
    1917                 :     {
    1918            7144 :       o->newline() << lvalue << " = ";
    1919            7144 :       rvalue->visit (this);
    1920            7144 :       o->line() << ";";
    1921                 :     }
    1922            9711 :   else if (rvalue->type == pe_string)
    1923                 :     {
    1924            9711 :       c_strcpy (lvalue, rvalue);
    1925                 :     }
    1926                 :   else
    1927                 :     {
    1928               0 :       string fullmsg = msg + " type unsupported";
    1929               0 :       throw semantic_error (fullmsg, rvalue->tok);
    1930                 :     }
    1931           16855 : }
    1932                 : 
    1933                 : 
    1934                 : void
    1935                 : c_unparser::c_assign (const string& lvalue, const string& rvalue,
    1936            2854 :                       exp_type type, const string& msg, const token* tok)
    1937                 : {
    1938            2854 :   if (type == pe_long)
    1939                 :     {
    1940            2135 :       o->newline() << lvalue << " = " << rvalue << ";";
    1941                 :     }
    1942             719 :   else if (type == pe_string)
    1943                 :     {
    1944             719 :       c_strcpy (lvalue, rvalue);
    1945                 :     }
    1946                 :   else
    1947                 :     {
    1948               0 :       string fullmsg = msg + " type unsupported";
    1949               0 :       throw semantic_error (fullmsg, tok);
    1950                 :     }
    1951            2854 : }
    1952                 : 
    1953                 : 
    1954                 : void 
    1955                 : c_unparser_assignment::c_assignop(tmpvar & res, 
    1956                 :                                   var const & lval, 
    1957                 :                                   tmpvar const & rval,
    1958            6393 :                                   token const * tok)
    1959                 : {
    1960                 :   // This is common code used by scalar and array-element assignments.
    1961                 :   // It assumes an operator-and-assignment (defined by the 'pre' and
    1962                 :   // 'op' fields of c_unparser_assignment) is taking place between the
    1963                 :   // following set of variables:
    1964                 :   //
    1965                 :   // res: the result of evaluating the expression, a temporary
    1966                 :   // lval: the lvalue of the expression, which may be damaged
    1967                 :   // rval: the rvalue of the expression, which is a temporary or constant
    1968                 : 
    1969                 :   // we'd like to work with a local tmpvar so we can overwrite it in 
    1970                 :   // some optimized cases
    1971                 : 
    1972            6393 :   translator_output* o = parent->o;
    1973                 : 
    1974            6393 :   if (res.type() == pe_string)
    1975                 :     {
    1976            3769 :       if (post)
    1977                 :         throw semantic_error ("post assignment on strings not supported", 
    1978               0 :                               tok);
    1979            3769 :       if (op == "=")
    1980                 :         {
    1981            3754 :           parent->c_strcpy (lval.value(), rval.value());
    1982                 :           // no need for second copy
    1983            3754 :           res = rval;
    1984                 :         }
    1985              15 :       else if (op == ".=")
    1986                 :         {
    1987              15 :           parent->c_strcat (lval.value(), rval.value());
    1988              30 :           res = lval;
    1989                 :         }
    1990                 :       else
    1991                 :         throw semantic_error ("string assignment operator " +
    1992               0 :                               op + " unsupported", tok);
    1993                 :     }
    1994            2624 :   else if (op == "<<<")
    1995                 :     {
    1996             175 :       assert(lval.type() == pe_stats);
    1997             175 :       assert(rval.type() == pe_long);
    1998             175 :       assert(res.type() == pe_long);
    1999             175 :       o->newline() << res << " = " << rval << ";";
    2000             175 :       o->newline() << "_stp_stat_add (" << lval << ", " << res << ");";
    2001                 :     }
    2002            2449 :   else if (res.type() == pe_long)
    2003                 :     {
    2004                 :       // a lot of operators come through this "gate":
    2005                 :       // - vanilla assignment "="
    2006                 :       // - stats aggregation "<<<"
    2007                 :       // - modify-accumulate "+=" and many friends
    2008                 :       // - pre/post-crement "++"/"--"
    2009                 :       // - "/" and "%" operators, but these need special handling in kernel
    2010                 : 
    2011                 :       // compute the modify portion of a modify-accumulate
    2012            2449 :       string macop;
    2013            2449 :       unsigned oplen = op.size();
    2014            2449 :       if (op == "=")
    2015            1657 :         macop = "*error*"; // special shortcuts below
    2016             792 :       else if (op == "++" || op == "+=")
    2017             697 :         macop = "+=";
    2018              95 :       else if (op == "--" || op == "-=")
    2019              77 :         macop = "-=";
    2020              18 :       else if (oplen > 1 && op[oplen-1] == '=') // for *=, <<=, etc...
    2021              18 :         macop = op;
    2022                 :       else
    2023                 :         // internal error
    2024               0 :         throw semantic_error ("unknown macop for assignment", tok);
    2025                 : 
    2026            2449 :       if (post)
    2027                 :         {
    2028             649 :           if (macop == "/" || macop == "%" || op == "=")
    2029               0 :             throw semantic_error ("invalid post-mode operator", tok);
    2030                 : 
    2031             649 :           o->newline() << res << " = " << lval << ";";
    2032                 : 
    2033             649 :           if (macop == "+=" || macop == "-=")
    2034             649 :             o->newline() << lval << " " << macop << " " << rval << ";";
    2035                 :           else
    2036               0 :             o->newline() << lval << " = " << res << " " << macop << " " << rval << ";";
    2037                 :         }
    2038                 :       else
    2039                 :         {
    2040            1800 :           if (op == "=") // shortcut simple assignment
    2041                 :             {
    2042            1657 :               o->newline() << lval << " = " << rval << ";";
    2043            1657 :               res = rval;
    2044                 :             }
    2045                 :           else
    2046                 :             {
    2047             143 :               if (macop == "/=")
    2048                 :                 o->newline() << lval << " = _stp_div64 (&c->last_error, "
    2049               3 :                              << lval << ", " << rval << ");";
    2050             140 :               else if (macop == "%=")
    2051                 :                 o->newline() << lval << " = _stp_mod64 (&c->last_error, "
    2052               3 :                              << lval << ", " << rval << ");";
    2053                 :               else
    2054             137 :                 o->newline() << lval << " " << macop << " " << rval << ";";
    2055             143 :               res = lval;
    2056                 :             }
    2057            2449 :         }
    2058                 :     }
    2059                 :     else
    2060               0 :       throw semantic_error ("assignment type not yet implemented", tok);
    2061            6393 : }
    2062                 : 
    2063                 : 
    2064                 : void 
    2065           19999 : c_unparser::c_declare(exp_type ty, const string &name) 
    2066                 : {
    2067           19999 :   o->newline() << c_typename (ty) << " " << c_varname (name) << ";";
    2068           19999 : }
    2069                 : 
    2070                 : 
    2071                 : void 
    2072               0 : c_unparser::c_declare_static(exp_type ty, const string &name) 
    2073                 : {
    2074               0 :   o->newline() << "static " << c_typename (ty) << " " << c_varname (name) << ";";
    2075               0 : }
    2076                 : 
    2077                 : 
    2078                 : void 
    2079            4886 : c_unparser::c_strcpy (const string& lvalue, const string& rvalue) 
    2080                 : {
    2081                 :   o->newline() << "strlcpy (" 
    2082                 :                    << lvalue << ", " 
    2083            4886 :                    << rvalue << ", MAXSTRINGLEN);";
    2084            4886 : }
    2085                 : 
    2086                 : 
    2087                 : void 
    2088            9711 : c_unparser::c_strcpy (const string& lvalue, expression* rvalue) 
    2089                 : {
    2090            9711 :   o->newline() << "strlcpy (" << lvalue << ", ";
    2091            9711 :   rvalue->visit (this);
    2092            9711 :   o->line() << ", MAXSTRINGLEN);";
    2093            9711 : }
    2094                 : 
    2095                 : 
    2096                 : void 
    2097              15 : c_unparser::c_strcat (const string& lvalue, const string& rvalue) 
    2098                 : {
    2099                 :   o->newline() << "strlcat (" 
    2100                 :                << lvalue << ", " 
    2101              15 :                << rvalue << ", MAXSTRINGLEN);";
    2102              15 : }
    2103                 : 
    2104                 : 
    2105                 : void 
    2106             265 : c_unparser::c_strcat (const string& lvalue, expression* rvalue) 
    2107                 : {
    2108             265 :   o->newline() << "strlcat (" << lvalue << ", ";
    2109             265 :   rvalue->visit (this);
    2110             265 :   o->line() << ", MAXSTRINGLEN);";
    2111             265 : }
    2112                 : 
    2113                 : 
    2114                 : bool
    2115           19462 : c_unparser::is_local(vardecl const *r, token const *tok)
    2116                 : {  
    2117           19462 :   if (current_probe)
    2118                 :     {
    2119           47653 :       for (unsigned i=0; i<current_probe->locals.size(); i++)
    2120                 :         {
    2121           43107 :           if (current_probe->locals[i] == r)
    2122           11216 :             return true;
    2123                 :         }
    2124                 :     }
    2125            3700 :   else if (current_function)
    2126                 :     {
    2127            2851 :       for (unsigned i=0; i<current_function->locals.size(); i++)
    2128                 :         {
    2129            1359 :           if (current_function->locals[i] == r)
    2130             598 :             return true;
    2131                 :         }
    2132                 : 
    2133            1664 :       for (unsigned i=0; i<current_function->formal_args.size(); i++)
    2134                 :         {
    2135            1498 :           if (current_function->formal_args[i] == r)
    2136            1326 :             return true;
    2137                 :         }
    2138                 :     }
    2139                 : 
    2140           64556 :   for (unsigned i=0; i<session->globals.size(); i++)
    2141                 :     {
    2142           64555 :       if (session->globals[i] == r)
    2143            6321 :         return false;
    2144                 :     }
    2145                 :   
    2146               1 :   if (tok)
    2147               1 :     throw semantic_error ("unresolved symbol", tok);
    2148                 :   else
    2149               0 :     throw semantic_error ("unresolved symbol: " + r->name);
    2150                 : }
    2151                 : 
    2152                 : 
    2153                 : tmpvar 
    2154           69239 : c_unparser::gensym(exp_type ty) 
    2155                 : { 
    2156           69239 :   return tmpvar (ty, tmpvar_counter); 
    2157                 : }
    2158                 : 
    2159                 : aggvar 
    2160             632 : c_unparser::gensym_aggregate() 
    2161                 : { 
    2162             632 :   return aggvar (tmpvar_counter); 
    2163                 : }
    2164                 : 
    2165                 : 
    2166                 : var 
    2167           16488 : c_unparser::getvar(vardecl *v, token const *tok) 
    2168                 : { 
    2169           16488 :   bool loc = is_local (v, tok);
    2170           16487 :   if (loc)    
    2171           13140 :     return var (loc, v->type, v->name);
    2172                 :   else
    2173                 :     {
    2174            3347 :       statistic_decl sd;
    2175            3347 :       std::map<std::string, statistic_decl>::const_iterator i;
    2176            3347 :       i = session->stat_decls.find(v->name);
    2177            3347 :       if (i != session->stat_decls.end())
    2178            1288 :         sd = i->second;
    2179            3347 :       return var (loc, v->type, sd, v->name);
    2180                 :     }
    2181                 : }
    2182                 : 
    2183                 : 
    2184                 : mapvar 
    2185            2974 : c_unparser::getmap(vardecl *v, token const *tok) 
    2186                 : {   
    2187            2974 :   if (v->arity < 1)
    2188               0 :     throw semantic_error("attempt to use scalar where map expected", tok);
    2189            2974 :   statistic_decl sd;
    2190            2974 :   std::map<std::string, statistic_decl>::const_iterator i;
    2191            2974 :   i = session->stat_decls.find(v->name);
    2192            2974 :   if (i != session->stat_decls.end())
    2193             309 :     sd = i->second;
    2194                 :   return mapvar (is_local (v, tok), v->type, sd,
    2195            2974 :       v->name, v->index_types, v->maxsize);
    2196                 : }
    2197                 : 
    2198                 : 
    2199                 : itervar 
    2200             204 : c_unparser::getiter(symbol *s)
    2201                 : { 
    2202             204 :   return itervar (s, tmpvar_counter);
    2203                 : }
    2204                 : 
    2205                 : 
    2206                 : 
    2207                 : // An artificial common "header" for each statement.  This is where
    2208                 : // activity counts limits and error state early exits are enforced.
    2209                 : void
    2210           15209 : c_unparser::visit_statement (statement *s, unsigned actions, bool stmtize)
    2211                 : {
    2212                 :   // For some constructs, it is important to avoid an error branch
    2213                 :   // right to the bottom of the probe/function.  The foreach()
    2214                 :   // iteration construct is one example.  Instead, if we are nested
    2215                 :   // within a loop, we branch merely to its "break" label.  The next
    2216                 :   // statement will branch one level higher, and so on, until we can
    2217                 :   // go straight "out".
    2218           15209 :   string outlabel = "out";
    2219           30418 :   unsigned loops = loop_break_labels.size();
    2220           15209 :   if (loops > 0)
    2221             375 :     outlabel = loop_break_labels[loops-1];
    2222                 : 
    2223           15209 :   if (s)
    2224                 :     {
    2225           15004 :       o->newline() << "if (unlikely (c->last_error)) goto " << outlabel << ";";
    2226           15004 :       assert (s->tok);
    2227           15004 :       if (stmtize)
    2228               0 :         o->newline() << "c->last_stmt = " << lex_cast_qstring(*s->tok) << ";";
    2229                 :     }
    2230                 : 
    2231           15209 :   if (actions > 0)
    2232                 :     {
    2233           15209 :       o->newline() << "c->actionremaining -= " << actions << ";";
    2234                 :       // XXX: This check is inserted too frequently.
    2235           15209 :       o->newline() << "if (unlikely (c->actionremaining <= 0)) {";
    2236           15209 :       o->newline(1) << "c->last_error = \"MAXACTION exceeded\";";
    2237           15209 :       o->newline() << "goto " << outlabel << ";";
    2238           15209 :       o->newline(-1) << "}";
    2239           15209 :     }
    2240           15209 : }
    2241                 : 
    2242                 : 
    2243                 : void
    2244            2895 : c_unparser::visit_block (block *s)
    2245                 : {
    2246            2895 :   o->newline() << "{";
    2247            2895 :   o->indent (1);
    2248                 : 
    2249                 :   // visit_statement (s, 0, false);
    2250                 :   //
    2251                 :   // NB: this is not necessary, since the last_error can be handled
    2252                 :   // just as easily by the first real body statement, and the
    2253                 :   // last_stmt won't be used since this nesting structure cannot
    2254                 :   // itself cause an error.
    2255                 : 
    2256           17963 :   for (unsigned i=0; i<s->statements.size(); i++)
    2257                 :     {
    2258                 :       try
    2259                 :         {
    2260           15068 :           s->statements[i]->visit (this);
    2261           15066 :           o->newline();
    2262                 :         }
    2263               4 :       catch (const semantic_error& e)
    2264                 :         {
    2265               2 :           session->print_error (e);
    2266                 :         }
    2267                 :     }
    2268            2895 :   o->newline(-1) << "}";
    2269            2895 : }
    2270                 : 
    2271                 : 
    2272                 : void
    2273            1052 : c_unparser::visit_embeddedcode (embeddedcode *s)
    2274                 : {
    2275                 :   // visit_statement (s, 1, true); 
    2276                 :   //
    2277                 :   // NB: this is not necessary, since this can occur only at the top
    2278                 :   // level of a function (so no errors can be pending), and the
    2279                 :   // action-count is already incremented at the point of call.
    2280                 : 
    2281            1052 :   o->newline() << "{";
    2282            1052 :   o->newline(1) << s->code;
    2283            1052 :   o->newline(-1) << "}";
    2284            1052 : }
    2285                 : 
    2286                 : 
    2287                 : void
    2288            3764 : c_unparser::visit_null_statement (null_statement *)
    2289                 : {
    2290                 :   // visit_statement (s, 0, false);
    2291                 :   //
    2292                 :   // NB: this is not necessary, since the last_error can be handled just as
    2293                 :   // easily by the next statement, and the last_stmt won't be used since this
    2294                 :   // statement cannot cause an error.
    2295                 : 
    2296            3764 :   o->newline() << "/* null */;";
    2297            3764 : }
    2298                 : 
    2299                 : 
    2300                 : void
    2301           10319 : c_unparser::visit_expr_statement (expr_statement *s)
    2302                 : {
    2303           10319 :   visit_statement (s, 1, false);
    2304           10319 :   o->newline() << "(void) ";
    2305           10319 :   s->value->visit (this);
    2306           10319 :   o->line() << ";";
    2307           10319 : }
    2308                 : 
    2309                 : 
    2310                 : void
    2311            3092 : c_unparser::visit_if_statement (if_statement *s)
    2312                 : {
    2313            3092 :   visit_statement (s, 1, false);
    2314            3092 :   o->newline() << "if (";
    2315            3092 :   o->indent (1);
    2316            3092 :   s->condition->visit (this);
    2317            3092 :   o->indent (-1);
    2318            3092 :   o->line() << ") {";
    2319            3092 :   o->indent (1);
    2320            3092 :   s->thenblock->visit (this);
    2321            3092 :   o->newline(-1) << "}";
    2322            3092 :   if (s->elseblock)
    2323                 :     {
    2324             815 :       o->newline() << "else {";
    2325             815 :       o->indent (1);
    2326             815 :       s->elseblock->visit (this);
    2327             815 :       o->newline(-1) << "}";
    2328                 :     }
    2329            3092 : }
    2330                 : 
    2331                 : 
    2332                 : void
    2333            2897 : c_tmpcounter::visit_block (block *s)
    2334                 : {
    2335                 :   // Key insight: individual statements of a block can reuse
    2336                 :   // temporary variable slots, since temporaries don't survive
    2337                 :   // statement boundaries.  So we use gcc's anonymous union/struct
    2338                 :   // facility to explicitly overlay the temporaries.
    2339            2897 :   parent->o->newline() << "union {";
    2340            2897 :   parent->o->indent(1);
    2341           17967 :   for (unsigned i=0; i<s->statements.size(); i++)
    2342                 :     {
    2343                 :       // To avoid lots of empty structs inside the union, remember
    2344                 :       // where we are now.  Then, output the struct start and remember
    2345                 :       // that positon.  If when we get done with the statement we
    2346                 :       // haven't moved, then we don't really need the struct.  To get
    2347                 :       // rid of the struct start we output, we'll seek back to where
    2348                 :       // we were before we output the struct.
    2349           15071 :       std::ostream::pos_type before_struct_pos = parent->o->tellp();
    2350           15071 :       parent->o->newline() << "struct {";
    2351           15071 :       parent->o->indent(1);
    2352           15071 :       std::ostream::pos_type after_struct_pos = parent->o->tellp();
    2353           15071 :       s->statements[i]->visit (this);
    2354           15070 :       parent->o->indent(-1);
    2355           15070 :       if (after_struct_pos == parent->o->tellp())
    2356            7632 :         parent->o->seekp(before_struct_pos);
    2357                 :       else
    2358            7438 :         parent->o->newline() << "};";
    2359                 :     }
    2360            2896 :   parent->o->newline(-1) << "};";
    2361            2896 : }
    2362                 : 
    2363                 : void
    2364             103 : c_tmpcounter::visit_for_loop (for_loop *s)
    2365                 : {
    2366             103 :   if (s->init) s->init->visit (this);
    2367             103 :   s->cond->visit (this);
    2368             103 :   s->block->visit (this);
    2369             103 :   if (s->incr) s->incr->visit (this);
    2370             103 : }
    2371                 : 
    2372                 : 
    2373                 : void
    2374             103 : c_unparser::visit_for_loop (for_loop *s)
    2375                 : {
    2376             103 :   visit_statement (s, 1, false);
    2377                 : 
    2378             103 :   string ctr = stringify (label_counter++);
    2379             103 :   string toplabel = "top_" + ctr;
    2380             103 :   string contlabel = "continue_" + ctr;
    2381             103 :   string breaklabel = "break_" + ctr;
    2382                 : 
    2383                 :   // initialization
    2384             103 :   if (s->init) s->init->visit (this);
    2385                 : 
    2386                 :   // condition
    2387             103 :   o->newline(-1) << toplabel << ":";
    2388                 : 
    2389                 :   // Emit an explicit action here to cover the act of iteration.
    2390                 :   // Equivalently, it can stand for the evaluation of the condition
    2391                 :   // expression.
    2392             103 :   o->indent(1);
    2393             103 :   visit_statement (0, 1, false);
    2394                 : 
    2395             103 :   o->newline() << "if (! (";
    2396             103 :   if (s->cond->type != pe_long)
    2397               0 :     throw semantic_error ("expected numeric type", s->cond->tok);
    2398             103 :   s->cond->visit (this);
    2399             103 :   o->line() << ")) goto " << breaklabel << ";";
    2400                 : 
    2401                 :   // body
    2402             103 :   loop_break_labels.push_back (breaklabel);
    2403             103 :   loop_continue_labels.push_back (contlabel);
    2404             103 :   s->block->visit (this);
    2405             103 :   loop_break_labels.pop_back ();
    2406             103 :   loop_continue_labels.pop_back ();
    2407                 : 
    2408                 :   // iteration
    2409             103 :   o->newline(-1) << contlabel << ":";
    2410             103 :   o->indent(1);
    2411             103 :   if (s->incr) s->incr->visit (this);
    2412             103 :   o->newline() << "goto " << toplabel << ";";
    2413                 : 
    2414                 :   // exit
    2415             103 :   o->newline(-1) << breaklabel << ":";
    2416             103 :   o->newline(1) << "; /* dummy statement */";
    2417             103 : }
    2418                 : 
    2419                 : 
    2420                 : struct arrayindex_downcaster
    2421                 :   : public traversing_visitor
    2422             262 : {
    2423                 :   arrayindex *& arr;
    2424                 :   
    2425             262 :   arrayindex_downcaster (arrayindex *& arr)
    2426             262 :     : arr(arr) 
    2427             262 :   {}
    2428                 : 
    2429             262 :   void visit_arrayindex (arrayindex* e)
    2430                 :   {
    2431             262 :     arr = e;
    2432             262 :   }
    2433                 : };
    2434                 : 
    2435                 : 
    2436                 : static bool
    2437                 : expression_is_arrayindex (expression *e, 
    2438             262 :                           arrayindex *& hist)
    2439                 : {
    2440             262 :   arrayindex *h = NULL;
    2441             262 :   arrayindex_downcaster d(h);
    2442             262 :   e->visit (&d);
    2443             262 :   if (static_cast<void*>(h) == static_cast<void*>(e))
    2444                 :     {
    2445             262 :       hist = h;
    2446             262 :       return true;
    2447                 :     }
    2448               0 :   return false;
    2449                 : }
    2450                 : 
    2451                 : 
    2452                 : void
    2453             108 : c_tmpcounter::visit_foreach_loop (foreach_loop *s)
    2454                 : {
    2455                 :   symbol *array;  
    2456                 :   hist_op *hist;
    2457             108 :   classify_indexable (s->base, array, hist);
    2458                 : 
    2459             108 :   if (array)
    2460                 :     {
    2461             102 :       itervar iv = parent->getiter (array);
    2462             102 :       parent->o->newline() << iv.declare();
    2463                 :     }
    2464                 :   else
    2465                 :    { 
    2466                 :      // See commentary in c_tmpcounter::visit_arrayindex for
    2467                 :      // discussion of tmpvars required to look into @hist_op(...)
    2468                 :      // expressions.
    2469                 : 
    2470                 :      // First make sure we have exactly one pe_long variable to use as
    2471                 :      // our bucket index.
    2472                 :      
    2473               6 :      if (s->indexes.size() != 1 || s->indexes[0]->referent->type != pe_long)
    2474               0 :        throw semantic_error("Invalid indexing of histogram", s->tok);
    2475                 :       
    2476                 :       // Then declare what we need to form the aggregate we're
    2477                 :       // iterating over, and all the tmpvars needed by our call to
    2478                 :       // load_aggregate().
    2479                 : 
    2480               6 :       aggvar agg = parent->gensym_aggregate ();
    2481               6 :       agg.declare(*(this->parent));
    2482                 : 
    2483               6 :       symbol *sym = get_symbol_within_expression (hist->stat);
    2484               6 :       var v = parent->getvar(sym->referent, sym->tok);
    2485               6 :       if (sym->referent->arity != 0)
    2486                 :         {
    2487               0 :           arrayindex *arr = NULL;
    2488               0 :           if (!expression_is_arrayindex (hist->stat, arr))
    2489               0 :             throw semantic_error("expected arrayindex expression in iterated hist_op", s->tok);
    2490                 : 
    2491               0 :           for (unsigned i=0; i<sym->referent->index_types.size(); i++)
    2492                 :             {         
    2493               0 :               tmpvar ix = parent->gensym (sym->referent->index_types[i]);
    2494               0 :               ix.declare (*parent);
    2495               0 :               arr->indexes[i]->visit(this);
    2496                 :             }
    2497               6 :         }
    2498                 :     }
    2499                 : 
    2500                 :   // Create a temporary for the loop limit counter and the limit
    2501                 :   // expression result.
    2502             108 :   if (s->limit)
    2503                 :     {
    2504              18 :       tmpvar res_limit = parent->gensym (pe_long);
    2505              18 :       res_limit.declare(*parent);
    2506                 : 
    2507              18 :       s->limit->visit (this);
    2508                 : 
    2509              18 :       tmpvar limitv = parent->gensym (pe_long);
    2510              18 :       limitv.declare(*parent);
    2511                 :     }
    2512                 : 
    2513             108 :   s->block->visit (this);
    2514             108 : }
    2515                 : 
    2516                 : void
    2517             108 : c_unparser::visit_foreach_loop (foreach_loop *s)
    2518                 : {
    2519                 :   symbol *array;  
    2520                 :   hist_op *hist;
    2521             108 :   classify_indexable (s->base, array, hist);
    2522                 : 
    2523             108 :   if (array)
    2524                 :     {
    2525             102 :       visit_statement (s, 1, false);
    2526                 :       
    2527             102 :       mapvar mv = getmap (array->referent, s->tok);
    2528             102 :       itervar iv = getiter (array);
    2529             102 :       vector<var> keys;
    2530                 :       
    2531             102 :       string ctr = stringify (label_counter++);
    2532             102 :       string toplabel = "top_" + ctr;
    2533             102 :       string contlabel = "continue_" + ctr;
    2534             102 :       string breaklabel = "break_" + ctr;
    2535                 :       
    2536                 :       // NB: structure parallels for_loop
    2537                 :       
    2538                 :       // initialization
    2539                 : 
    2540             102 :       tmpvar *res_limit = NULL;
    2541             102 :       if (s->limit)
    2542                 :         {
    2543                 :           // Evaluate the limit expression once.
    2544              17 :           res_limit = new tmpvar(gensym(pe_long));
    2545              34 :           c_assign (res_limit->value(), s->limit, "foreach limit");
    2546                 :         }
    2547                 :       
    2548                 :       // aggregate array if required
    2549             102 :       if (mv.is_parallel())
    2550                 :         {
    2551              23 :           o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << "))";
    2552              23 :           o->newline(1) << "c->last_error = \"aggregation overflow in " << mv << "\";";
    2553              23 :           o->indent(-1);
    2554                 : 
    2555                 :           // sort array if desired
    2556              23 :           if (s->sort_direction)
    2557                 :             {
    2558                 :               int sort_column;
    2559                 : 
    2560                 :               // If the user wanted us to sort by value, we'll sort by
    2561                 :               // @count instead for aggregates.  '-5' tells the
    2562                 :               // runtime to sort by count.
    2563              16 :               if (s->sort_column == 0)
    2564               8 :                 sort_column = -5;
    2565                 :               else
    2566               8 :                 sort_column = s->sort_column;
    2567                 : 
    2568              16 :               o->newline() << "else"; // only sort if aggregation was ok
    2569              16 :               if (s->limit)
    2570                 :                 {
    2571                 :                   o->newline(1) << "_stp_map_sortn ("
    2572                 :                                 << mv.fetch_existing_aggregate() << ", "
    2573                 :                                 << *res_limit << ", " << sort_column << ", "
    2574               7 :                                 << - s->sort_direction << ");";
    2575                 :                 }
    2576                 :               else
    2577                 :                 {
    2578                 :                   o->newline(1) << "_stp_map_sort ("
    2579                 :                                 << mv.fetch_existing_aggregate() << ", "
    2580                 :                                 << sort_column << ", "
    2581               9 :                                 << - s->sort_direction << ");";
    2582                 :                 }
    2583              16 :               o->indent(-1);
    2584                 :             }
    2585                 :         }
    2586                 :       else
    2587                 :         {      
    2588                 :           // sort array if desired
    2589              79 :           if (s->sort_direction)
    2590                 :             {
    2591              22 :               if (s->limit)
    2592                 :                 {
    2593                 :                   o->newline() << "_stp_map_sortn (" << mv.value() << ", "
    2594                 :                                << *res_limit << ", " << s->sort_column << ", "
    2595               8 :                                << - s->sort_direction << ");";
    2596                 :                 }
    2597                 :               else
    2598                 :                 {
    2599                 :                   o->newline() << "_stp_map_sort (" << mv.value() << ", "
    2600                 :                                << s->sort_column << ", "
    2601              14 :                                << - s->sort_direction << ");";
    2602                 :                 }
    2603                 :             }
    2604                 :         }
    2605                 : 
    2606                 :       // NB: sort direction sense is opposite in runtime, thus the negation
    2607                 :       
    2608             102 :       if (mv.is_parallel())
    2609              23 :         aggregations_active.insert(mv.value());
    2610             102 :       o->newline() << iv << " = " << iv.start (mv) << ";";
    2611                 :       
    2612             102 :       tmpvar *limitv = NULL;
    2613             102 :       if (s->limit)
    2614                 :       {
    2615                 :           // Create the loop limit variable here and initialize it.
    2616              17 :           limitv = new tmpvar(gensym (pe_long));
    2617              34 :           o->newline() << *limitv << " = 0LL;";
    2618                 :       }
    2619                 : 
    2620                 :       // condition
    2621             102 :       o->newline(-1) << toplabel << ":";
    2622                 : 
    2623                 :       // Emit an explicit action here to cover the act of iteration.
    2624                 :       // Equivalently, it can stand for the evaluation of the
    2625                 :       // condition expression.
    2626             102 :       o->indent(1);
    2627             102 :       visit_statement (0, 1, false);
    2628                 : 
    2629             102 :       o->newline() << "if (! (" << iv << ")) goto " << breaklabel << ";";
    2630                 :       
    2631                 :       // body
    2632             102 :       loop_break_labels.push_back (breaklabel);
    2633             102 :       loop_continue_labels.push_back (contlabel);
    2634             102 :       o->newline() << "{";
    2635             102 :       o->indent (1);
    2636                 : 
    2637             102 :       if (s->limit)
    2638                 :       {
    2639                 :           // If we've been through LIMIT loop iterations, quit.
    2640                 :           o->newline() << "if (" << *limitv << "++ >= " << *res_limit
    2641              17 :                        << ") goto " << breaklabel << ";";
    2642                 : 
    2643                 :           // We're done with limitv and res_limit.
    2644              17 :           delete limitv;
    2645              17 :           delete res_limit;
    2646                 :       }
    2647                 : 
    2648             226 :       for (unsigned i = 0; i < s->indexes.size(); ++i)
    2649                 :         {
    2650                 :           // copy the iter values into the specified locals
    2651             124 :           var v = getvar (s->indexes[i]->referent);
    2652             124 :           c_assign (v, iv.get_key (v.type(), i), s->tok);
    2653                 :         }
    2654             102 :       s->block->visit (this);
    2655             102 :       o->newline(-1) << "}";
    2656             102 :       loop_break_labels.pop_back ();
    2657             102 :       loop_continue_labels.pop_back ();
    2658                 :       
    2659                 :       // iteration
    2660             102 :       o->newline(-1) << contlabel << ":";
    2661             102 :       o->newline(1) << iv << " = " << iv.next (mv) << ";";
    2662             102 :       o->newline() << "goto " << toplabel << ";";
    2663                 :       
    2664                 :       // exit
    2665             102 :       o->newline(-1) << breaklabel << ":";
    2666             102 :       o->newline(1) << "; /* dummy statement */";
    2667                 : 
    2668             102 :       if (mv.is_parallel())
    2669              23 :         aggregations_active.erase(mv.value());
    2670                 :     }
    2671                 :   else
    2672                 :     {
    2673                 :       // Iterating over buckets in a histogram.
    2674               6 :       assert(s->indexes.size() == 1);
    2675               6 :       assert(s->indexes[0]->referent->type == pe_long);
    2676               6 :       var bucketvar = getvar (s->indexes[0]->referent);
    2677                 : 
    2678               6 :       aggvar agg = gensym_aggregate ();
    2679               6 :       load_aggregate(hist->stat, agg);
    2680                 : 
    2681               6 :       symbol *sym = get_symbol_within_expression (hist->stat);
    2682               6 :       var v = getvar(sym->referent, sym->tok);
    2683               6 :       v.assert_hist_compatible(*hist);
    2684                 : 
    2685               6 :       tmpvar *res_limit = NULL;
    2686               6 :       tmpvar *limitv = NULL;
    2687               6 :       if (s->limit)
    2688                 :         {
    2689                 :           // Evaluate the limit expression once.
    2690               1 :           res_limit = new tmpvar(gensym(pe_long));
    2691               2 :           c_assign (res_limit->value(), s->limit, "foreach limit");
    2692                 : 
    2693                 :           // Create the loop limit variable here and initialize it.
    2694               2 :           limitv = new tmpvar(gensym (pe_long));
    2695               2 :           o->newline() << *limitv << " = 0LL;";
    2696                 :         }
    2697                 :       
    2698                 :       // XXX: break / continue don't work here yet
    2699                 :       o->newline() << "for (" << bucketvar << " = 0; " 
    2700                 :                    << bucketvar << " < " << v.buckets() << "; "
    2701               6 :                    << bucketvar << "++) { ";
    2702               6 :       o->newline(1);
    2703                 : 
    2704               6 :       if (s->limit)
    2705                 :       {
    2706                 :           // If we've been through LIMIT loop iterations, quit.
    2707                 :           o->newline() << "if (" << *limitv << "++ >= " << *res_limit
    2708               1 :                        << ") break;";
    2709                 : 
    2710                 :           // We're done with limitv and res_limit.
    2711               1 :           delete limitv;
    2712               1 :           delete res_limit;
    2713                 :       }
    2714                 : 
    2715               6 :       s->block->visit (this);
    2716               6 :       o->newline(-1) << "}";
    2717                 :     }
    2718             108 : }
    2719                 : 
    2720                 : 
    2721                 : void
    2722            1102 : c_unparser::visit_return_statement (return_statement* s)
    2723                 : {
    2724            1102 :   visit_statement (s, 1, false);
    2725                 : 
    2726            1102 :   if (current_function == 0)
    2727               0 :     throw semantic_error ("cannot 'return' from probe", s->tok);
    2728                 : 
    2729            1102 :   if (s->value->type != current_function->type)
    2730                 :     throw semantic_error ("return type mismatch", current_function->tok,
    2731               0 :                          "vs", s->tok);
    2732                 : 
    2733            1102 :   c_assign ("l->__retvalue", s->value, "return value");
    2734            1102 :   o->newline() << "c->last_error = \"\";";
    2735                 :   // NB: last_error needs to get reset to NULL in the caller
    2736                 :   // probe/function
    2737            1102 : }
    2738                 : 
    2739                 : 
    2740                 : void
    2741              18 : c_unparser::visit_next_statement (next_statement* s)
    2742                 : {
    2743              18 :   visit_statement (s, 1, false);
    2744                 : 
    2745              18 :   if (current_probe == 0)
    2746               0 :     throw semantic_error ("cannot 'next' from function", s->tok);
    2747                 : 
    2748              18 :   o->newline() << "c->last_error = \"\";";
    2749              18 : }
    2750                 : 
    2751                 : 
    2752                 : struct delete_statement_operand_tmp_visitor:
    2753                 :   public traversing_visitor
    2754             258 : {
    2755                 :   c_tmpcounter *parent;
    2756             258 :   delete_statement_operand_tmp_visitor (c_tmpcounter *p):
    2757             258 :     parent (p)
    2758             258 :   {}
    2759                 :   //void visit_symbol (symbol* e);
    2760                 :   void visit_arrayindex (arrayindex* e);
    2761                 : };
    2762                 : 
    2763                 : 
    2764                 : struct delete_statement_operand_visitor:
    2765                 :   public throwing_visitor
    2766             258 : {
    2767                 :   c_unparser *parent;
    2768             258 :   delete_statement_operand_visitor (c_unparser *p):
    2769                 :     throwing_visitor ("invalid operand of delete expression"),
    2770             258 :     parent (p)
    2771             258 :   {}
    2772                 :   void visit_symbol (symbol* e);
    2773                 :   void visit_arrayindex (arrayindex* e);
    2774                 : };
    2775                 : 
    2776                 : void 
    2777              78 : delete_statement_operand_visitor::visit_symbol (symbol* e)
    2778                 : {
    2779              78 :   assert (e->referent != 0);
    2780              78 :   if (e->referent->arity > 0)
    2781                 :     {
    2782              19 :       mapvar mvar = parent->getmap(e->referent, e->tok);  
    2783                 :       /* NB: Memory deallocation/allocation operations
    2784                 :        are not generally safe.
    2785                 :       parent->o->newline() << mvar.fini ();
    2786                 :       parent->o->newline() << mvar.init ();  
    2787                 :       */
    2788              19 :       if (mvar.is_parallel())
    2789               7 :         parent->o->newline() << "_stp_pmap_clear (" << mvar.value() << ");";
    2790                 :       else
    2791              12 :         parent->o->newline() << "_stp_map_clear (" << mvar.value() << ");";
    2792                 :     }
    2793                 :   else
    2794                 :     {
    2795              59 :       var v = parent->getvar(e->referent, e->tok);  
    2796              59 :       switch (e->type)
    2797                 :         {
    2798                 :         case pe_stats:
    2799              55 :           parent->o->newline() << "_stp_stat_clear (" << v.value() << ");";
    2800              55 :           break;
    2801                 :         case pe_long:
    2802               2 :           parent->o->newline() << v.value() << " = 0;";
    2803               2 :           break;
    2804                 :         case pe_string:
    2805               2 :           parent->o->newline() << v.value() << "[0] = '\\0';";
    2806               2 :           break;
    2807                 :         case pe_unknown:
    2808                 :         default:
    2809               0 :           throw semantic_error("Cannot delete unknown expression type", e->tok);
    2810              59 :         }
    2811                 :     }
    2812              78 : }
    2813                 : 
    2814                 : void 
    2815             180 : delete_statement_operand_tmp_visitor::visit_arrayindex (arrayindex* e)
    2816                 : {
    2817                 :   symbol *array;  
    2818                 :   hist_op *hist;
    2819             180 :   classify_indexable (e->base, array, hist);
    2820                 : 
    2821             180 :   if (array)
    2822                 :     {
    2823             180 :       assert (array->referent != 0);
    2824             180 :       vardecl* r = array->referent;
    2825                 : 
    2826                 :       // One temporary per index dimension.
    2827             433 :       for (unsigned i=0; i<r->index_types.size(); i++)
    2828                 :         {
    2829             253 :           tmpvar ix = parent->parent->gensym (r->index_types[i]);
    2830             253 :           ix.declare (*(parent->parent));
    2831             253 :           e->indexes[i]->visit(parent);
    2832                 :         }
    2833                 :     }
    2834                 :   else
    2835                 :     {
    2836               0 :       throw semantic_error("cannot delete histogram bucket entries\n", e->tok);
    2837                 :     }
    2838             180 : }
    2839                 : 
    2840                 : void 
    2841             180 : delete_statement_operand_visitor::visit_arrayindex (arrayindex* e)
    2842                 : {
    2843                 :   symbol *array;  
    2844                 :   hist_op *hist;
    2845             180 :   classify_indexable (e->base, array, hist);
    2846                 : 
    2847             180 :   if (array)
    2848                 :     {
    2849             180 :       vector<tmpvar> idx;
    2850             180 :       parent->load_map_indices (e, idx);
    2851                 :       
    2852                 :       {
    2853             180 :         mapvar mvar = parent->getmap (array->referent, e->tok);
    2854             180 :         parent->o->newline() << mvar.del (idx) << ";";
    2855             180 :       }
    2856                 :     }
    2857                 :   else
    2858                 :     {
    2859               0 :       throw semantic_error("cannot delete histogram bucket entries\n", e->tok);
    2860                 :     }
    2861             180 : }
    2862                 : 
    2863                 : 
    2864                 : void
    2865             258 : c_tmpcounter::visit_delete_statement (delete_statement* s)
    2866                 : {
    2867             258 :   delete_statement_operand_tmp_visitor dv (this);
    2868             258 :   s->value->visit (&dv);
    2869             258 : }
    2870                 : 
    2871                 : 
    2872                 : void
    2873             258 : c_unparser::visit_delete_statement (delete_statement* s)
    2874                 : {
    2875             258 :   visit_statement (s, 1, false);
    2876             258 :   delete_statement_operand_visitor dv (this);
    2877             258 :   s->value->visit (&dv);
    2878             258 : }
    2879                 : 
    2880                 : 
    2881                 : void
    2882               5 : c_unparser::visit_break_statement (break_statement* s)
    2883                 : {
    2884               5 :   visit_statement (s, 1, false);
    2885               5 :   if (loop_break_labels.size() == 0)
    2886               1 :     throw semantic_error ("cannot 'break' outside loop", s->tok);
    2887                 : 
    2888               4 :   string label = loop_break_labels[loop_break_labels.size()-1];
    2889               4 :   o->newline() << "goto " << label << ";";
    2890               4 : }
    2891                 : 
    2892                 : 
    2893                 : void
    2894               5 : c_unparser::visit_continue_statement (continue_statement* s)
    2895                 : {
    2896               5 :   visit_statement (s, 1, false);
    2897               5 :   if (loop_continue_labels.size() == 0)
    2898               1 :     throw semantic_error ("cannot 'continue' outside loop", s->tok);
    2899                 : 
    2900               4 :   string label = loop_continue_labels[loop_continue_labels.size()-1];
    2901               4 :   o->newline() << "goto " << label << ";";
    2902               4 : }
    2903                 : 
    2904                 : 
    2905                 : 
    2906                 : void
    2907            4763 : c_unparser::visit_literal_string (literal_string* e)
    2908                 : {
    2909            4763 :   const string& v = e->value;
    2910            4763 :   o->line() << '"';
    2911           39479 :   for (unsigned i=0; i<v.size(); i++)
    2912                 :     // NB: The backslash character is specifically passed through as is.
    2913                 :     // This is because our parser treats "\" as an ordinary character, not
    2914                 :     // an escape sequence, leaving it to the C compiler (and this function)
    2915                 :     // to treat it as such.  If we were to escape it, there would be no way
    2916                 :     // of generating C-level escapes from script code.
    2917                 :     // See also print_format::components_to_string and lex_cast_qstring
    2918           34716 :     if (v[i] == '"') // or other escapeworthy characters?
    2919               2 :       o->line() << '\\' << '"';
    2920                 :     else
    2921           34714 :       o->line() << v[i];
    2922            4763 :   o->line() << '"';
    2923            4763 : }
    2924                 : 
    2925                 : 
    2926                 : void
    2927            4180 : c_unparser::visit_literal_number (literal_number* e)
    2928                 : {
    2929                 :   // This looks ugly, but tries to be warning-free on 32- and 64-bit
    2930                 :   // hosts.
    2931                 :   // NB: this needs to be signed!
    2932            4180 :   if (e->value == -9223372036854775807LL-1) // PR 5023
    2933               8 :     o->line() << "((int64_t)" << (unsigned long long) e->value << "ULL)";
    2934                 :   else
    2935            4172 :     o->line() << "((int64_t)" << e->value << "LL)";
    2936            4180 : }
    2937                 : 
    2938                 : 
    2939                 : void
    2940             585 : c_tmpcounter::visit_binary_expression (binary_expression* e)
    2941                 : {
    2942             585 :   if (e->op == "/" || e->op == "%")
    2943                 :     {
    2944              89 :       tmpvar left = parent->gensym (pe_long);
    2945              89 :       tmpvar right = parent->gensym (pe_long);
    2946              89 :       if (e->left->tok->type != tok_number)
    2947              68 :         left.declare (*parent);
    2948              89 :       if (e->right->tok->type != tok_number)
    2949              30 :         right.declare (*parent);
    2950                 :     }
    2951                 : 
    2952             585 :   e->left->visit (this);
    2953             585 :   e->right->visit (this);
    2954             585 : }
    2955                 : 
    2956                 : 
    2957                 : void
    2958             585 : c_unparser::visit_binary_expression (binary_expression* e)
    2959                 : {
    2960             585 :   if (e->type != pe_long ||
    2961                 :       e->left->type != pe_long ||
    2962                 :       e->right->type != pe_long)
    2963               0 :     throw semantic_error ("expected numeric types", e->tok);
    2964                 :   
    2965             585 :   if (e->op == "+" ||
    2966                 :       e->op == "-" ||
    2967                 :       e->op == "*" ||
    2968                 :       e->op == "&" ||
    2969                 :       e->op == "|" ||
    2970                 :       e->op == "^")
    2971                 :     {
    2972             487 :       o->line() << "((";
    2973             487 :       e->left->visit (this);
    2974             487 :       o->line() << ") " << e->op << " (";
    2975             487 :       e->right->visit (this);
    2976             487 :       o->line() << "))";
    2977                 :     }
    2978              98 :   else if (e->op == ">>" ||
    2979                 :            e->op == "<<")
    2980                 :     {
    2981               9 :       o->line() << "((";
    2982               9 :       e->left->visit (this);
    2983               9 :       o->line() << ") " << e->op << "max(min(";
    2984               9 :       e->right->visit (this);
    2985               9 :       o->line() << ", (int64_t)64LL), (int64_t)0LL))"; // between 0 and 64
    2986                 :     }
    2987              89 :   else if (e->op == "/" ||
    2988                 :            e->op == "%")
    2989                 :     {
    2990                 :       // % and / need a division-by-zero check; and thus two temporaries
    2991                 :       // for proper evaluation order
    2992              89 :       tmpvar left = gensym (pe_long);
    2993              89 :       tmpvar right = gensym (pe_long);
    2994                 : 
    2995              89 :       o->line() << "({";
    2996              89 :       o->indent(1);
    2997                 :       // NB: Need last_stmt set here because of possible last_error generation
    2998              89 :       o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    2999                 : 
    3000              89 :       if (e->left->tok->type == tok_number)
    3001              21 :         left.override(c_expression(e->left));
    3002                 :       else
    3003                 :         {
    3004              68 :           o->newline() << left << " = ";
    3005              68 :           e->left->visit (this);
    3006              68 :           o->line() << ";";
    3007                 :         }
    3008                 : 
    3009              89 :       if (e->right->tok->type == tok_number)
    3010              59 :         right.override(c_expression(e->right));
    3011                 :       else
    3012                 :         {
    3013              30 :           o->newline() << right << " = ";
    3014              30 :           e->right->visit (this);
    3015              30 :           o->line() << ";";
    3016                 :         }
    3017                 : 
    3018                 :       o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64")
    3019              89 :                    << " (&c->last_error, " << left << ", " << right << ");";
    3020                 : 
    3021              89 :       o->newline(-1) << "})";
    3022                 :     }
    3023                 :   else
    3024               0 :     throw semantic_error ("operator not yet implemented", e->tok); 
    3025             585 : }
    3026                 : 
    3027                 : 
    3028                 : void
    3029             228 : c_unparser::visit_unary_expression (unary_expression* e)
    3030                 : {
    3031             228 :   if (e->type != pe_long ||
    3032                 :       e->operand->type != pe_long)
    3033               0 :     throw semantic_error ("expected numeric types", e->tok);
    3034                 : 
    3035             228 :   if (e->op == "-")
    3036                 :     {
    3037                 :       // NB: Subtraction is special, since negative literals in the
    3038                 :       // script language show up as unary negations over positive
    3039                 :       // literals here.  This makes it "exciting" for emitting pure
    3040                 :       // C since: - 0x8000_0000_0000_0000 ==> - (- 9223372036854775808)
    3041                 :       // This would constitute a signed overflow, which gcc warns on
    3042                 :       // unless -ftrapv/-J are in CFLAGS - which they're not.
    3043                 : 
    3044             131 :       o->line() << "(int64_t)(0 " << e->op << " (uint64_t)(";
    3045             131 :       e->operand->visit (this);
    3046             131 :       o->line() << "))";
    3047                 :     }
    3048                 :   else
    3049                 :     {
    3050              97 :       o->line() << "(" << e->op << " (";
    3051              97 :       e->operand->visit (this);
    3052              97 :       o->line() << "))";
    3053                 :     }
    3054             228 : }
    3055                 : 
    3056                 : void
    3057               4 : c_unparser::visit_logical_or_expr (logical_or_expr* e)
    3058                 : {
    3059               4 :   if (e->type != pe_long ||
    3060                 :       e->left->type != pe_long ||
    3061                 :       e->right->type != pe_long)
    3062               0 :     throw semantic_error ("expected numeric types", e->tok);
    3063                 : 
    3064               4 :   o->line() << "((";
    3065               4 :   e->left->visit (this);
    3066               4 :   o->line() << ") " << e->op << " (";
    3067               4 :   e->right->visit (this);
    3068               4 :   o->line() << "))";
    3069               4 : }
    3070                 : 
    3071                 : 
    3072                 : void
    3073              31 : c_unparser::visit_logical_and_expr (logical_and_expr* e)
    3074                 : {
    3075              31 :   if (e->type != pe_long ||
    3076                 :       e->left->type != pe_long ||
    3077                 :       e->right->type != pe_long)
    3078               0 :     throw semantic_error ("expected numeric types", e->tok);
    3079                 : 
    3080              31 :   o->line() << "((";
    3081              31 :   e->left->visit (this);
    3082              31 :   o->line() << ") " << e->op << " (";
    3083              31 :   e->right->visit (this);
    3084              31 :   o->line() << "))";
    3085              31 : }
    3086                 : 
    3087                 : 
    3088                 : void 
    3089              43 : c_tmpcounter::visit_array_in (array_in* e)
    3090                 : {
    3091                 :   symbol *array;  
    3092                 :   hist_op *hist;
    3093              43 :   classify_indexable (e->operand->base, array, hist);
    3094                 :   
    3095              43 :   if (array)
    3096                 :     {
    3097              42 :       assert (array->referent != 0);
    3098              42 :       vardecl* r = array->referent;
    3099                 : 
    3100                 :       // One temporary per index dimension.
    3101              95 :       for (unsigned i=0; i<r->index_types.size(); i++)
    3102                 :         {
    3103              53 :           tmpvar ix = parent->gensym (r->index_types[i]);
    3104              53 :           ix.declare (*parent);
    3105              53 :           e->operand->indexes[i]->visit(this);
    3106                 :         }
    3107                 :       
    3108                 :       // A boolean result.
    3109              42 :       tmpvar res = parent->gensym (e->type);
    3110              42 :       res.declare (*parent);
    3111                 :     }
    3112                 :   else
    3113                 :     {
    3114                 :       // By definition:
    3115                 :       //
    3116                 :       // 'foo in @hist_op(...)'  is true iff
    3117                 :       // '@hist_op(...)[foo]'    is nonzero
    3118                 :       //
    3119                 :       // so we just delegate to the latter call, since int64_t is also
    3120                 :       // our boolean type.
    3121               1 :       e->operand->visit(this);
    3122                 :     }
    3123              43 : }
    3124                 : 
    3125                 : 
    3126                 : void
    3127              43 : c_unparser::visit_array_in (array_in* e)
    3128                 : {
    3129                 :   symbol *array;  
    3130                 :   hist_op *hist;
    3131              43 :   classify_indexable (e->operand->base, array, hist);
    3132                 :   
    3133              43 :   if (array)
    3134                 :     {
    3135              42 :       stmt_expr block(*this);  
    3136                 :       
    3137              42 :       vector<tmpvar> idx;
    3138              42 :       load_map_indices (e->operand, idx);
    3139                 :       // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3140                 :       
    3141              42 :       tmpvar res = gensym (pe_long);
    3142              42 :       mapvar mvar = getmap (array->referent, e->tok);
    3143              42 :       c_assign (res, mvar.exists(idx), e->tok);
    3144                 : 
    3145              42 :       o->newline() << res << ";";
    3146                 :     }
    3147                 :   else
    3148                 :     {
    3149                 :       // By definition:
    3150                 :       //
    3151                 :       // 'foo in @hist_op(...)'  is true iff
    3152                 :       // '@hist_op(...)[foo]'    is nonzero
    3153                 :       //
    3154                 :       // so we just delegate to the latter call, since int64_t is also
    3155                 :       // our boolean type.
    3156               1 :       e->operand->visit(this);
    3157                 :     }
    3158              43 : }
    3159                 : 
    3160                 : 
    3161                 : void
    3162            2598 : c_unparser::visit_comparison (comparison* e)
    3163                 : {
    3164            2598 :   o->line() << "(";
    3165                 : 
    3166            2598 :   if (e->left->type == pe_string)
    3167                 :     {
    3168             993 :       if (e->left->type != pe_string ||
    3169                 :           e->right->type != pe_string)
    3170               0 :         throw semantic_error ("expected string types", e->tok);
    3171                 : 
    3172             993 :       o->line() << "strncmp (";
    3173             993 :       e->left->visit (this);
    3174             993 :       o->line() << ", ";
    3175             993 :       e->right->visit (this);
    3176             993 :       o->line() << ", MAXSTRINGLEN";
    3177             993 :       o->line() << ") " << e->op << " 0";
    3178                 :     }
    3179            1605 :   else if (e->left->type == pe_long)
    3180                 :     {
    3181            1605 :       if (e->left->type != pe_long ||
    3182                 :           e->right->type != pe_long)
    3183               0 :         throw semantic_error ("expected numeric types", e->tok);
    3184                 : 
    3185            1605 :       o->line() << "((";
    3186            1605 :       e->left->visit (this);
    3187            1605 :       o->line() << ") " << e->op << " (";
    3188            1605 :       e->right->visit (this);
    3189            1605 :       o->line() << "))";
    3190                 :     }
    3191                 :   else
    3192               0 :     throw semantic_error ("unexpected type", e->left->tok);
    3193                 : 
    3194            2598 :   o->line() << ")";
    3195            2598 : }
    3196                 : 
    3197                 : 
    3198                 : void
    3199             265 : c_tmpcounter::visit_concatenation (concatenation* e)
    3200                 : {
    3201             265 :   tmpvar t = parent->gensym (e->type);
    3202             265 :   t.declare (*parent);
    3203             265 :   e->left->visit (this);
    3204             265 :   e->right->visit (this);
    3205             265 : }
    3206                 : 
    3207                 : 
    3208                 : void
    3209             265 : c_unparser::visit_concatenation (concatenation* e)
    3210                 : {
    3211             265 :   if (e->op != ".")
    3212               0 :     throw semantic_error ("unexpected concatenation operator", e->tok);
    3213                 : 
    3214             265 :   if (e->type != pe_string ||
    3215                 :       e->left->type != pe_string ||
    3216                 :       e->right->type != pe_string)
    3217               0 :     throw semantic_error ("expected string types", e->tok);
    3218                 : 
    3219             265 :   tmpvar t = gensym (e->type);
    3220                 :   
    3221             265 :   o->line() << "({ ";
    3222             265 :   o->indent(1);
    3223                 :   // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3224             265 :   c_assign (t.value(), e->left, "assignment");
    3225             530 :   c_strcat (t.value(), e->right);
    3226             265 :   o->newline() << t << ";";
    3227             265 :   o->newline(-1) << "})";
    3228             265 : }
    3229                 : 
    3230                 : 
    3231                 : void
    3232              30 : c_unparser::visit_ternary_expression (ternary_expression* e)
    3233                 : {
    3234              30 :   if (e->cond->type != pe_long)
    3235               0 :     throw semantic_error ("expected numeric condition", e->cond->tok);
    3236                 : 
    3237              30 :   if (e->truevalue->type != e->falsevalue->type ||
    3238                 :       e->type != e->truevalue->type ||
    3239                 :       (e->truevalue->type != pe_long && e->truevalue->type != pe_string))
    3240               0 :     throw semantic_error ("expected matching types", e->tok);
    3241                 : 
    3242              30 :   o->line() << "((";
    3243              30 :   e->cond->visit (this);
    3244              30 :   o->line() << ") ? (";
    3245              30 :   e->truevalue->visit (this);
    3246              30 :   o->line() << ") : (";
    3247              30 :   e->falsevalue->visit (this);
    3248              30 :   o->line() << "))";
    3249              30 : }
    3250                 : 
    3251                 : 
    3252                 : void
    3253            5710 : c_tmpcounter::visit_assignment (assignment *e)
    3254                 : {
    3255            5710 :   c_tmpcounter_assignment tav (this, e->op, e->right);
    3256            5710 :   e->left->visit (& tav);
    3257            5710 : }
    3258                 : 
    3259                 : 
    3260                 : void
    3261            5709 : c_unparser::visit_assignment (assignment* e)
    3262                 : {
    3263            5709 :   if (e->op == "<<<")
    3264                 :     {
    3265             240 :       if (e->type != pe_long)
    3266               0 :         throw semantic_error ("non-number <<< expression", e->tok);
    3267                 : 
    3268             240 :       if (e->left->type != pe_stats)
    3269               0 :         throw semantic_error ("non-stats left operand to <<< expression", e->left->tok);
    3270                 : 
    3271             240 :       if (e->right->type != pe_long)
    3272               0 :         throw semantic_error ("non-number right operand to <<< expression", e->right->tok);
    3273                 :         
    3274                 :     }
    3275                 :   else
    3276                 :     {
    3277            5469 :       if (e->type != e->left->type)
    3278                 :         throw semantic_error ("type mismatch", e->tok,
    3279               0 :                               "vs", e->left->tok);
    3280            5469 :       if (e->right->type != e->left->type)
    3281                 :         throw semantic_error ("type mismatch", e->right->tok,
    3282               0 :                               "vs", e->left->tok);
    3283                 :     }
    3284                 : 
    3285            5709 :   c_unparser_assignment tav (this, e->op, e->right);
    3286            5709 :   e->left->visit (& tav);
    3287            5709 : }
    3288                 : 
    3289                 : 
    3290                 : void
    3291             100 : c_tmpcounter::visit_pre_crement (pre_crement* e)
    3292                 : {
    3293             100 :   c_tmpcounter_assignment tav (this, e->op, 0);
    3294             100 :   e->operand->visit (& tav);
    3295             100 : }
    3296                 : 
    3297                 : 
    3298                 : void
    3299             100 : c_unparser::visit_pre_crement (pre_crement* e)
    3300                 : {
    3301             100 :   if (e->type != pe_long ||
    3302                 :       e->type != e->operand->type)
    3303               0 :     throw semantic_error ("expected numeric type", e->tok);
    3304                 : 
    3305             100 :   c_unparser_assignment tav (this, e->op, false);
    3306             100 :   e->operand->visit (& tav);
    3307             100 : }
    3308                 : 
    3309                 : 
    3310                 : void
    3311             649 : c_tmpcounter::visit_post_crement (post_crement* e)
    3312                 : {
    3313             649 :   c_tmpcounter_assignment tav (this, e->op, 0, true);
    3314             649 :   e->operand->visit (& tav);
    3315             649 : }
    3316                 : 
    3317                 : 
    3318                 : void
    3319             649 : c_unparser::visit_post_crement (post_crement* e)
    3320                 : {
    3321             649 :   if (e->type != pe_long ||
    3322                 :       e->type != e->operand->type)
    3323               0 :     throw semantic_error ("expected numeric type", e->tok);
    3324                 : 
    3325             649 :   c_unparser_assignment tav (this, e->op, true);
    3326             649 :   e->operand->visit (& tav);
    3327             649 : }
    3328                 : 
    3329                 : 
    3330                 : void
    3331            9380 : c_unparser::visit_symbol (symbol* e)
    3332                 : {
    3333            9380 :   assert (e->referent != 0);
    3334            9380 :   vardecl* r = e->referent;
    3335                 : 
    3336            9380 :   if (r->index_types.size() != 0)
    3337               0 :     throw semantic_error ("invalid reference to array", e->tok);
    3338                 : 
    3339            9380 :   var v = getvar(r, e->tok);
    3340            9380 :   o->line() << v;
    3341            9380 : }
    3342                 : 
    3343                 : 
    3344                 : void
    3345            6459 : c_tmpcounter_assignment::prepare_rvalue (tmpvar & rval)
    3346                 : {
    3347            6459 :   if (rvalue)
    3348                 :     {
    3349                 :       // literal number and strings don't need any temporaries declared
    3350            5710 :       if (rvalue->tok->type != tok_number && rvalue->tok->type != tok_string)
    3351            2958 :         rval.declare (*(parent->parent));
    3352                 : 
    3353            5710 :       rvalue->visit (parent);
    3354                 :     }
    3355            6459 : }
    3356                 : 
    3357                 : void 
    3358            6394 : c_tmpcounter_assignment::c_assignop(tmpvar & res)
    3359                 : {
    3360            6394 :   if (res.type() == pe_string)
    3361                 :     {
    3362                 :       // string assignment doesn't need any temporaries declared
    3363                 :     }
    3364            2625 :   else if (op == "<<<")
    3365             175 :     res.declare (*(parent->parent));
    3366            2450 :   else if (res.type() == pe_long)
    3367                 :     {
    3368                 :       // Only the 'post' operators ('x++') need a temporary declared.
    3369            2450 :       if (post)
    3370             649 :         res.declare (*(parent->parent));
    3371                 :     }
    3372            6394 : }
    3373                 : 
    3374                 : // Assignment expansion is tricky.
    3375                 : //
    3376                 : // Because assignments are nestable expressions, we have
    3377                 : // to emit C constructs that are nestable expressions too.
    3378                 : // We have to evaluate the given expressions the proper number of times,
    3379                 : // including array indices.
    3380                 : // We have to lock the lvalue (if global) against concurrent modification,
    3381                 : // especially with modify-assignment operations (+=, ++).
    3382                 : // We have to check the rvalue (for division-by-zero checks).
    3383                 : 
    3384                 : // In the normal "pre=false" case, for (A op B) emit:
    3385                 : // ({ tmp = B; check(B); lock(A); res = A op tmp; A = res; unlock(A); res; })
    3386                 : // In the "pre=true" case, emit instead:
    3387                 : // ({ tmp = B; check(B); lock(A); res = A; A = res op tmp; unlock(A); res; })
    3388                 : //
    3389                 : // (op is the plain operator portion of a combined calculate/assignment:
    3390                 : // "+" for "+=", and so on.  It is in the "macop" variable below.)
    3391                 : //
    3392                 : // For array assignments, additional temporaries are used for each
    3393                 : // index, which are expanded before the "tmp=B" expression, in order
    3394                 : // to consistently order evaluation of lhs before rhs.
    3395                 : //
    3396                 : 
    3397                 : void
    3398            5435 : c_tmpcounter_assignment::visit_symbol (symbol *e)
    3399                 : {
    3400            5435 :   exp_type ty = rvalue ? rvalue->type : e->type;
    3401            5435 :   tmpvar rval = parent->parent->gensym (ty);
    3402            5435 :   tmpvar res = parent->parent->gensym (ty);
    3403                 : 
    3404            5435 :   prepare_rvalue(rval);
    3405                 : 
    3406            5435 :   c_assignop (res);
    3407            5435 : }
    3408                 : 
    3409                 : 
    3410                 : void
    3411                 : c_unparser_assignment::prepare_rvalue (string const & op, 
    3412                 :                                        tmpvar & rval,
    3413            6458 :                                        token const * tok)
    3414                 : {
    3415            6458 :   if (rvalue)
    3416                 :     {
    3417            8460 :       if (rvalue->tok->type == tok_number || rvalue->tok->type == tok_string)
    3418                 :         // Instead of assigning the numeric or string constant to a
    3419                 :         // temporary, then assigning the temporary to the final, let's
    3420                 :         // just override the temporary with the constant.
    3421            2751 :         rval.override(parent->c_expression(rvalue));
    3422                 :       else
    3423            2958 :         parent->c_assign (rval.value(), rvalue, "assignment");
    3424                 :     }
    3425                 :   else
    3426                 :     {
    3427             749 :       if (op == "++" || op == "--")
    3428                 :         // Here is part of the conversion proccess of turning "x++" to
    3429                 :         // "x += 1".
    3430             749 :         rval.override("1");
    3431                 :       else
    3432               0 :         throw semantic_error ("need rvalue for assignment", tok);
    3433                 :     }
    3434            6458 : }
    3435                 : 
    3436                 : void
    3437            5435 : c_unparser_assignment::visit_symbol (symbol *e)
    3438                 : {
    3439            5435 :   stmt_expr block(*parent);
    3440                 : 
    3441            5435 :   assert (e->referent != 0);
    3442            5435 :   if (e->referent->index_types.size() != 0)
    3443               0 :     throw semantic_error ("unexpected reference to array", e->tok);
    3444                 : 
    3445                 :   // parent->o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3446            5435 :   exp_type ty = rvalue ? rvalue->type : e->type;
    3447            5435 :   tmpvar rval = parent->gensym (ty);
    3448            5435 :   tmpvar res = parent->gensym (ty);
    3449                 : 
    3450            5435 :   prepare_rvalue (op, rval, e->tok);
    3451                 : 
    3452            5435 :   var lvar = parent->getvar (e->referent, e->tok);
    3453            5435 :   c_assignop (res, lvar, rval, e->tok);     
    3454                 : 
    3455            5435 :   parent->o->newline() << res << ";";
    3456            5435 : }
    3457                 : 
    3458                 : 
    3459                 : void 
    3460               0 : c_unparser::visit_target_symbol (target_symbol* e)
    3461                 : {
    3462               0 :   throw semantic_error("cannot translate general target-symbol expression", e->tok);
    3463                 : }
    3464                 : 
    3465                 : 
    3466                 : void
    3467            1675 : c_tmpcounter::load_map_indices(arrayindex *e)
    3468                 : {
    3469                 :   symbol *array;  
    3470                 :   hist_op *hist;
    3471            1675 :   classify_indexable (e->base, array, hist);
    3472                 : 
    3473            1675 :   if (array)
    3474                 :     {
    3475            1675 :       assert (array->referent != 0);
    3476            1675 :       vardecl* r = array->referent;
    3477                 :       
    3478                 :       // One temporary per index dimension, except in the case of
    3479                 :       // number or string constants.
    3480            3554 :       for (unsigned i=0; i<r->index_types.size(); i++)
    3481                 :         {
    3482            1879 :           tmpvar ix = parent->gensym (r->index_types[i]);
    3483            1879 :           if (e->indexes[i]->tok->type == tok_number
    3484                 :               || e->indexes[i]->tok->type == tok_string)
    3485                 :             {
    3486                 :               // Do nothing
    3487                 :             }
    3488                 :           else
    3489            1188 :             ix.declare (*parent);
    3490            1879 :           e->indexes[i]->visit(this);
    3491                 :         }
    3492                 :     }
    3493            1675 : }
    3494                 : 
    3495                 : 
    3496                 : void
    3497                 : c_unparser::load_map_indices(arrayindex *e,
    3498            2037 :                              vector<tmpvar> & idx)
    3499                 : {
    3500                 :   symbol *array;  
    3501                 :   hist_op *hist;
    3502            2037 :   classify_indexable (e->base, array, hist);
    3503                 : 
    3504            2037 :   if (array)
    3505                 :     {
    3506            2018 :       idx.clear();
    3507                 :       
    3508            2018 :       assert (array->referent != 0);
    3509            2018 :       vardecl* r = array->referent;
    3510                 :       
    3511            2018 :       if (r->index_types.size() == 0 ||
    3512                 :           r->index_types.size() != e->indexes.size())
    3513               0 :         throw semantic_error ("invalid array reference", e->tok);
    3514                 :       
    3515            4338 :       for (unsigned i=0; i<r->index_types.size(); i++)
    3516                 :         {
    3517            2320 :           if (r->index_types[i] != e->indexes[i]->type)
    3518               0 :             throw semantic_error ("array index type mismatch", e->indexes[i]->tok);
    3519                 :           
    3520            2320 :           tmpvar ix = gensym (r->index_types[i]);
    3521            2320 :           if (e->indexes[i]->tok->type == tok_number
    3522                 :               || e->indexes[i]->tok->type == tok_string)
    3523                 :             // Instead of assigning the numeric or string constant to a
    3524                 :             // temporary, then using the temporary, let's just
    3525                 :             // override the temporary with the constant.
    3526             756 :             ix.override(c_expression(e->indexes[i]));
    3527                 :           else
    3528                 :             {
    3529                 :               // o->newline() << "c->last_stmt = "
    3530                 :               // << lex_cast_qstring(*e->indexes[i]->tok) << ";";
    3531            1564 :               c_assign (ix.value(), e->indexes[i], "array index copy");
    3532                 :             }
    3533            2320 :           idx.push_back (ix);
    3534                 :         }
    3535                 :     }
    3536                 :   else
    3537                 :     {
    3538              19 :       assert (e->indexes.size() == 1);
    3539              19 :       assert (e->indexes[0]->type == pe_long);
    3540              19 :       tmpvar ix = gensym (pe_long);
    3541                 :       // o->newline() << "c->last_stmt = "
    3542                 :       //           << lex_cast_qstring(*e->indexes[0]->tok) << ";";
    3543              19 :       c_assign (ix.value(), e->indexes[0], "array index copy");
    3544              38 :       idx.push_back(ix);
    3545                 :     }  
    3546            2037 : }
    3547                 : 
    3548                 : 
    3549                 : void 
    3550             316 : c_unparser::load_aggregate (expression *e, aggvar & agg, bool pre_agg)
    3551                 : {
    3552             316 :   symbol *sym = get_symbol_within_expression (e);
    3553                 :   
    3554             316 :   if (sym->referent->type != pe_stats)
    3555               0 :     throw semantic_error ("unexpected aggregate of non-statistic", sym->tok);
    3556                 :   
    3557             316 :   var v = getvar(sym->referent, e->tok);
    3558                 : 
    3559             316 :   if (sym->referent->arity == 0)
    3560                 :     {
    3561                 :       // o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";";
    3562             193 :       o->newline() << agg << " = _stp_stat_get (" << v << ", 0);";         
    3563                 :     }
    3564                 :   else
    3565                 :     {
    3566             123 :       arrayindex *arr = NULL;
    3567             123 :       if (!expression_is_arrayindex (e, arr))
    3568               0 :         throw semantic_error("unexpected aggregate of non-arrayindex", e->tok);
    3569                 :       
    3570             123 :       vector<tmpvar> idx;
    3571             123 :       load_map_indices (arr, idx);
    3572             123 :       mapvar mvar = getmap (sym->referent, sym->tok);
    3573                 :       // o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";";
    3574             123 :       o->newline() << agg << " = " << mvar.get(idx, pre_agg) << ";";
    3575             316 :     }
    3576             316 : }
    3577                 : 
    3578                 : 
    3579                 : string 
    3580              19 : c_unparser::histogram_index_check(var & base, tmpvar & idx) const
    3581                 : {
    3582                 :   return "((" + idx.value() + " >= 0)"
    3583              19 :     + " && (" + idx.value() + " < " + base.buckets() + "))"; 
    3584                 : }
    3585                 : 
    3586                 : 
    3587                 : void
    3588             670 : c_tmpcounter::visit_arrayindex (arrayindex *e)
    3589                 : {
    3590                 :   symbol *array;  
    3591                 :   hist_op *hist;
    3592             670 :   classify_indexable (e->base, array, hist);
    3593                 : 
    3594             670 :   if (array)
    3595                 :     {
    3596             651 :       load_map_indices(e);
    3597                 :       
    3598                 :       // The index-expression result.
    3599             651 :       tmpvar res = parent->gensym (e->type);
    3600             651 :       res.declare (*parent);
    3601                 :     }
    3602                 :   else
    3603                 :     {
    3604                 : 
    3605              19 :       assert(hist);
    3606                 : 
    3607                 :       // Note: this is a slightly tricker-than-it-looks allocation of
    3608                 :       // temporaries. The reason is that we're in the branch handling
    3609                 :       // histogram-indexing, and the histogram might be build over an
    3610                 :       // indexable entity itself. For example if we have:
    3611                 :       // 
    3612                 :       //  global foo
    3613                 :       //  ...
    3614                 :       //  foo[getpid(), geteuid()] <<< 1
    3615                 :       //  ...
    3616                 :       //  print @log_hist(foo[pid, euid])[bucket]
    3617                 :       //  
    3618                 :       // We are looking at the @log_hist(...)[bucket] expression, so
    3619                 :       // allocating one tmpvar for calculating bucket (the "index" of
    3620                 :       // this arrayindex expression), and one tmpvar for storing the
    3621                 :       // result in, just as normal.
    3622                 :       //      
    3623                 :       // But we are *also* going to call load_aggregate on foo, which
    3624                 :       // will itself require tmpvars for each of its indices. Since
    3625                 :       // this is not handled by delving into the subexpression (it
    3626                 :       // would be if hist were first-class in the type system, but
    3627                 :       // it's not) we we allocate all the tmpvars used in such a
    3628                 :       // subexpression up here: first our own aggvar, then our index
    3629                 :       // (bucket) tmpvar, then all the index tmpvars of our
    3630                 :       // pe_stat-valued subexpression, then our result.
    3631                 : 
    3632                 :       
    3633                 :       // First all the stuff related to indexing into the histogram
    3634                 : 
    3635              19 :       if (e->indexes.size() != 1)
    3636               0 :         throw semantic_error("Invalid indexing of histogram", e->tok);
    3637              19 :       tmpvar ix = parent->gensym (pe_long);
    3638              19 :       ix.declare (*parent);      
    3639              19 :       e->indexes[0]->visit(this);
    3640              19 :       tmpvar res = parent->gensym (pe_long);
    3641              19 :       res.declare (*parent);
    3642                 :       
    3643                 :       // Then the aggregate, and all the tmpvars needed by our call to
    3644                 :       // load_aggregate().
    3645                 : 
    3646              19 :       aggvar agg = parent->gensym_aggregate ();
    3647              19 :       agg.declare(*(this->parent));
    3648                 : 
    3649              19 :       symbol *sym = get_symbol_within_expression (hist->stat);
    3650              19 :       var v = parent->getvar(sym->referent, sym->tok);
    3651              19 :       if (sym->referent->arity != 0)
    3652                 :         {
    3653               4 :           arrayindex *arr = NULL;
    3654               4 :           if (!expression_is_arrayindex (hist->stat, arr))
    3655               0 :             throw semantic_error("expected arrayindex expression in indexed hist_op", e->tok);
    3656                 : 
    3657               8 :           for (unsigned i=0; i<sym->referent->index_types.size(); i++)
    3658                 :             {         
    3659               4 :               tmpvar ix = parent->gensym (sym->referent->index_types[i]);
    3660               4 :               ix.declare (*parent);
    3661               4 :               arr->indexes[i]->visit(this);
    3662                 :             }
    3663              19 :         }
    3664                 :     }
    3665             670 : }
    3666                 : 
    3667                 : 
    3668                 : void
    3669             669 : c_unparser::visit_arrayindex (arrayindex* e)
    3670                 : {  
    3671                 :   symbol *array;  
    3672                 :   hist_op *hist;
    3673             669 :   classify_indexable (e->base, array, hist);
    3674                 : 
    3675             669 :   if (array)
    3676                 :     {
    3677                 :       // Visiting an statistic-valued array in a non-lvalue context is prohibited.
    3678             650 :       if (array->referent->type == pe_stats)
    3679               0 :         throw semantic_error ("statistic-valued array in rvalue context", e->tok);
    3680                 : 
    3681             650 :       stmt_expr block(*this);  
    3682                 : 
    3683                 :       // NB: Do not adjust the order of the next few lines; the tmpvar
    3684                 :       // allocation order must remain the same between
    3685                 :       // c_unparser::visit_arrayindex and c_tmpcounter::visit_arrayindex
    3686                 :       
    3687             650 :       vector<tmpvar> idx;
    3688             650 :       load_map_indices (e, idx);
    3689             650 :       tmpvar res = gensym (e->type);
    3690                 :   
    3691             650 :       mapvar mvar = getmap (array->referent, e->tok);
    3692                 :       // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3693             650 :       c_assign (res, mvar.get(idx), e->tok);
    3694                 : 
    3695             650 :       o->newline() << res << ";";
    3696                 :     }
    3697                 :   else
    3698                 :     {
    3699                 :       // See commentary in c_tmpcounter::visit_arrayindex
    3700                 : 
    3701              19 :       assert(hist);
    3702              19 :       stmt_expr block(*this);  
    3703                 : 
    3704                 :       // NB: Do not adjust the order of the next few lines; the tmpvar
    3705                 :       // allocation order must remain the same between
    3706                 :       // c_unparser::visit_arrayindex and c_tmpcounter::visit_arrayindex
    3707                 :       
    3708              19 :       vector<tmpvar> idx;
    3709              19 :       load_map_indices (e, idx);
    3710              19 :       tmpvar res = gensym (e->type);
    3711                 :       
    3712              19 :       aggvar agg = gensym_aggregate ();
    3713                 : 
    3714                 :       // These should have faulted during elaboration if not true.
    3715              19 :       assert(idx.size() == 1);
    3716              19 :       assert(idx[0].type() == pe_long); 
    3717                 : 
    3718              19 :       symbol *sym = get_symbol_within_expression (hist->stat);
    3719                 : 
    3720                 :       var *v;
    3721              19 :       if (sym->referent->arity < 1)
    3722              15 :         v = new var(getvar(sym->referent, e->tok));
    3723                 :       else
    3724               4 :         v = new mapvar(getmap(sym->referent, e->tok));
    3725                 : 
    3726              19 :       v->assert_hist_compatible(*hist);
    3727                 : 
    3728              19 :       if (aggregations_active.count(v->value()))
    3729               2 :         load_aggregate(hist->stat, agg, true);
    3730                 :       else 
    3731              17 :         load_aggregate(hist->stat, agg, false);
    3732                 : 
    3733              19 :       o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3734                 : 
    3735                 :       // PR 2142+2610: empty aggregates
    3736                 :       o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
    3737              19 :                    << " || " <<  agg.value() << "->count == 0)";
    3738              19 :       o->newline(1) << "c->last_error = \"empty aggregate\";";
    3739              19 :       o->newline(-1) << "else {";
    3740              19 :       o->newline(1) << "if (" << histogram_index_check(*v, idx[0]) << ")";
    3741              19 :       o->newline(1)  << res << " = " << agg << "->histogram[" << idx[0] << "];";
    3742              19 :       o->newline(-1) << "else";
    3743              19 :       o->newline(1)  << "c->last_error = \"histogram index out of range\";";
    3744                 : 
    3745              19 :       o->newline(-1) << "}";
    3746              19 :       o->newline(-1) << res << ";";
    3747                 :             
    3748              19 :       delete v;
    3749                 :     }
    3750             669 : }
    3751                 : 
    3752                 : 
    3753                 : void
    3754            1024 : c_tmpcounter_assignment::visit_arrayindex (arrayindex *e)
    3755                 : {
    3756                 :   symbol *array;  
    3757                 :   hist_op *hist;
    3758            1024 :   classify_indexable (e->base, array, hist);
    3759                 : 
    3760            1024 :   if (array)
    3761                 :     {
    3762            1024 :       parent->load_map_indices(e);
    3763                 :  
    3764                 :       // The expression rval, lval, and result.
    3765            1024 :       exp_type ty = rvalue ? rvalue->type : e->type;
    3766            1024 :       tmpvar rval = parent->parent->gensym (ty);
    3767            1024 :       tmpvar lval = parent->parent->gensym (ty);
    3768            1024 :       tmpvar res = parent->parent->gensym (ty);
    3769                 : 
    3770            1024 :       prepare_rvalue(rval);
    3771            1024 :       lval.declare (*(parent->parent));
    3772                 : 
    3773            1024 :       if (op == "<<<")
    3774              65 :         res.declare (*(parent->parent));
    3775                 :       else
    3776             959 :         c_assignop(res);
    3777                 :     }
    3778                 :   else
    3779                 :     {
    3780               0 :       throw semantic_error("cannot assign to histogram buckets", e->tok);
    3781                 :     }
    3782            1024 : }
    3783                 : 
    3784                 : 
    3785                 : void
    3786            1023 : c_unparser_assignment::visit_arrayindex (arrayindex *e)
    3787                 : {
    3788                 :   symbol *array;  
    3789                 :   hist_op *hist;
    3790            1023 :   classify_indexable (e->base, array, hist);
    3791                 : 
    3792            1023 :   if (array)
    3793                 :     {
    3794                 : 
    3795            1023 :       stmt_expr block(*parent);  
    3796                 : 
    3797            1023 :       translator_output *o = parent->o;
    3798                 : 
    3799            1023 :       if (array->referent->index_types.size() == 0)
    3800               0 :         throw semantic_error ("unexpected reference to scalar", e->tok);
    3801                 : 
    3802                 :       // nb: Do not adjust the order of the next few lines; the tmpvar
    3803                 :       // allocation order must remain the same between
    3804                 :       // c_unparser_assignment::visit_arrayindex and
    3805                 :       // c_tmpcounter_assignment::visit_arrayindex
    3806                 :   
    3807            1023 :       vector<tmpvar> idx;
    3808            1023 :       parent->load_map_indices (e, idx);
    3809            1023 :       exp_type ty = rvalue ? rvalue->type : e->type;
    3810            1023 :       tmpvar rvar = parent->gensym (ty);
    3811            1023 :       tmpvar lvar = parent->gensym (ty);
    3812            1023 :       tmpvar res = parent->gensym (ty);
    3813                 :   
    3814                 :       // NB: because these expressions are nestable, emit this construct
    3815                 :       // thusly:
    3816                 :       // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs); lvar; res;
    3817                 :       //    lock (array);
    3818                 :       //    lvar = get (array,idx0...N); // if necessary
    3819                 :       //    assignop (res, lvar, rvar);
    3820                 :       //    set (array, idx0...N, lvar);
    3821                 :       //    unlock (array);
    3822                 :       //    res; })
    3823                 :       //
    3824                 :       // we store all indices in temporary variables to avoid nasty
    3825                 :       // reentrancy issues that pop up with nested expressions:
    3826                 :       // e.g. ++a[a[c]=5] could deadlock
    3827                 :       //
    3828                 :       //
    3829                 :       // There is an exception to the above form: if we're doign a <<< assigment to 
    3830                 :       // a statistic-valued map, there's a special form we follow:
    3831                 :       //
    3832                 :       // ({ tmp0=(idx0); ... tmpN=(idxN); rvar=(rhs);
    3833                 :       //    *no need to* lock (array);
    3834                 :       //    _stp_map_add_stat (array, idx0...N, rvar);
    3835                 :       //    *no need to* unlock (array);
    3836                 :       //    rvar; })
    3837                 :       //
    3838                 :       // To simplify variable-allocation rules, we assign rvar to lvar and
    3839                 :       // res in this block as well, even though they are technically
    3840                 :       // superfluous.
    3841                 : 
    3842            1023 :       prepare_rvalue (op, rvar, e->tok);
    3843                 : 
    3844            1023 :       if (op == "<<<")
    3845                 :         {
    3846              65 :           assert (e->type == pe_stats);
    3847              65 :           assert (rvalue->type == pe_long);
    3848                 : 
    3849              65 :           mapvar mvar = parent->getmap (array->referent, e->tok);
    3850                 :           // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3851              65 :           o->newline() << mvar.add (idx, rvar) << ";";
    3852              65 :           res = rvar;
    3853                 :           // no need for these dummy assignments
    3854                 :           // o->newline() << lvar << " = " << rvar << ";";
    3855                 :           // o->newline() << res << " = " << rvar << ";";
    3856                 :         }
    3857                 :       else
    3858                 :         {
    3859             958 :           mapvar mvar = parent->getmap (array->referent, e->tok);
    3860                 :           // o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    3861             958 :           if (op != "=") // don't bother fetch slot if we will just overwrite it
    3862             228 :             parent->c_assign (lvar, mvar.get(idx), e->tok);
    3863             958 :           c_assignop (res, lvar, rvar, e->tok); 
    3864             958 :           o->newline() << mvar.set (idx, lvar) << ";";
    3865                 :         }
    3866                 : 
    3867            1023 :       o->newline() << res << ";";
    3868                 :     } 
    3869                 :   else
    3870                 :     {
    3871               0 :       throw semantic_error("cannot assign to histogram buckets", e->tok);
    3872                 :     }
    3873            1023 : }
    3874                 : 
    3875                 : 
    3876                 : void
    3877            8245 : c_tmpcounter::visit_functioncall (functioncall *e)
    3878                 : {
    3879            8245 :   assert (e->referent != 0);
    3880            8245 :   functiondecl* r = e->referent;
    3881                 :   // one temporary per argument, unless literal numbers or strings
    3882           11099 :   for (unsigned i=0; i<r->formal_args.size(); i++)
    3883                 :     {
    3884            2854 :       tmpvar t = parent->gensym (r->formal_args[i]->type);
    3885            2854 :       if (e->args[i]->tok->type != tok_number
    3886                 :           && e->args[i]->tok->type != tok_string)
    3887            1816 :         t.declare (*parent);
    3888            2854 :       e->args[i]->visit (this);
    3889                 :     }
    3890            8245 : }
    3891                 : 
    3892                 : 
    3893                 : void
    3894            8245 : c_unparser::visit_functioncall (functioncall* e)
    3895                 : {
    3896            8245 :   assert (e->referent != 0);
    3897            8245 :   functiondecl* r = e->referent;
    3898                 : 
    3899            8245 :   if (r->formal_args.size() != e->args.size())
    3900               0 :     throw semantic_error ("invalid length argument list", e->tok);
    3901                 : 
    3902            8245 :   stmt_expr block(*this);  
    3903                 : 
    3904                 :   // NB: we store all actual arguments in temporary variables,
    3905                 :   // to avoid colliding sharing of context variables with
    3906                 :   // nested function calls: f(f(f(1)))
    3907                 : 
    3908                 :   // compute actual arguments
    3909            8245 :   vector<tmpvar> tmp;
    3910                 : 
    3911           11099 :   for (unsigned i=0; i<e->args.size(); i++)
    3912                 :     {
    3913            2854 :       tmpvar t = gensym(e->args[i]->type);
    3914                 : 
    3915            2854 :       if (r->formal_args[i]->type != e->args[i]->type)
    3916                 :         throw semantic_error ("function argument type mismatch",
    3917               0 :                               e->args[i]->tok, "vs", r->formal_args[i]->tok);
    3918                 : 
    3919            2854 :       if (e->args[i]->tok->type == tok_number
    3920                 :           || e->args[i]->tok->type == tok_string)
    3921            1038 :         t.override(c_expression(e->args[i]));
    3922                 :       else
    3923                 :         {
    3924                 :           // o->newline() << "c->last_stmt = "
    3925                 :           // << lex_cast_qstring(*e->args[i]->tok) << ";";
    3926                 :           c_assign (t.value(), e->args[i],
    3927            1816 :                     "function actual argument evaluation");
    3928                 :         }
    3929            2854 :       tmp.push_back(t);
    3930                 :     }
    3931                 : 
    3932                 :   // copy in actual arguments
    3933           22198 :   for (unsigned i=0; i<e->args.size(); i++)
    3934                 :     {
    3935            2854 :       if (r->formal_args[i]->type != e->args[i]->type)
    3936                 :         throw semantic_error ("function argument type mismatch",
    3937               0 :                               e->args[i]->tok, "vs", r->formal_args[i]->tok);
    3938                 : 
    3939                 :       c_assign ("c->locals[c->nesting+1].function_" +
    3940                 :                 c_varname (r->name) + "." +
    3941                 :                 c_varname (r->formal_args[i]->name),
    3942                 :                 tmp[i].value(),
    3943                 :                 e->args[i]->type,
    3944                 :                 "function actual argument copy",
    3945            2854 :                 e->args[i]->tok);
    3946                 :     }
    3947                 : 
    3948                 :   // call function
    3949            8245 :   o->newline() << "function_" << c_varname (r->name) << " (c);";
    3950                 : 
    3951                 :   // return result from retvalue slot
    3952            8245 :   if (r->type == pe_unknown)
    3953                 :     // If we passed typechecking, then nothing will use this return value
    3954             562 :     o->newline() << "(void) 0;";
    3955                 :   else
    3956                 :     o->newline() << "c->locals[c->nesting+1]"
    3957                 :                  << ".function_" << c_varname (r->name)
    3958            7683 :                  << ".__retvalue;";
    3959            8245 : }
    3960                 : 
    3961                 : void
    3962            4666 : c_tmpcounter::visit_print_format (print_format* e)
    3963                 : {
    3964            4666 :   if (e->hist)
    3965                 :     {
    3966              87 :       symbol *sym = get_symbol_within_expression (e->hist->stat);
    3967              87 :       var v = parent->getvar(sym->referent, sym->tok);
    3968              87 :       aggvar agg = parent->gensym_aggregate ();
    3969                 : 
    3970              87 :       agg.declare(*(this->parent));
    3971                 : 
    3972              87 :       if (sym->referent->arity != 0)
    3973                 :         {
    3974                 :           // One temporary per index dimension.
    3975              18 :           for (unsigned i=0; i<sym->referent->index_types.size(); i++)
    3976                 :             {
    3977               9 :               arrayindex *arr = NULL;
    3978               9 :               if (!expression_is_arrayindex (e->hist->stat, arr))
    3979               0 :                 throw semantic_error("expected arrayindex expression in printed hist_op", e->tok);
    3980                 :               
    3981               9 :               tmpvar ix = parent->gensym (sym->referent->index_types[i]);
    3982               9 :               ix.declare (*parent);
    3983               9 :               arr->indexes[i]->visit(this);
    3984                 :             }
    3985              87 :         }
    3986                 :     }
    3987                 :   else
    3988                 :     {
    3989                 :       // One temporary per argument
    3990           14091 :       for (unsigned i=0; i < e->args.size(); i++)
    3991                 :         {
    3992            9513 :           tmpvar t = parent->gensym (e->args[i]->type);
    3993            9513 :           if (e->args[i]->type == pe_unknown)
    3994                 :             {
    3995                 :               throw semantic_error("unknown type of arg to print operator", 
    3996               0 :                                    e->args[i]->tok);
    3997                 :             }
    3998                 : 
    3999            9513 :           if (e->args[i]->tok->type != tok_number
    4000                 :               && e->args[i]->tok->type != tok_string)
    4001            9115 :             t.declare (*parent);
    4002            9513 :           e->args[i]->visit (this);
    4003                 :         }
    4004                 : 
    4005                 :       // And the result
    4006            4578 :       exp_type ty = e->print_to_stream ? pe_long : pe_string;
    4007            4578 :       tmpvar res = parent->gensym (ty);      
    4008            4578 :       if (ty == pe_string)
    4009            1230 :         res.declare (*parent);
    4010                 :     }
    4011            4665 : }
    4012                 : 
    4013                 : 
    4014                 : void 
    4015            4664 : c_unparser::visit_print_format (print_format* e)
    4016                 : {
    4017                 :   // Print formats can contain a general argument list *or* a special
    4018                 :   // type of argument which gets its own processing: a single,
    4019                 :   // non-format-string'ed, histogram-type stat_op expression.
    4020                 : 
    4021            4664 :   if (e->hist)
    4022                 :     {
    4023              87 :       stmt_expr block(*this);  
    4024              87 :       symbol *sym = get_symbol_within_expression (e->hist->stat);
    4025              87 :       aggvar agg = gensym_aggregate ();
    4026                 : 
    4027                 :       var *v;
    4028              87 :       if (sym->referent->arity < 1)
    4029              78 :         v = new var(getvar(sym->referent, e->tok));
    4030                 :       else
    4031               9 :         v = new mapvar(getmap(sym->referent, e->tok));
    4032                 : 
    4033              87 :       v->assert_hist_compatible(*e->hist);
    4034                 : 
    4035                 :       {
    4036              87 :         if (aggregations_active.count(v->value()))
    4037               4 :           load_aggregate(e->hist->stat, agg, true);
    4038                 :         else 
    4039              83 :           load_aggregate(e->hist->stat, agg, false);
    4040                 : 
    4041                 :         // PR 2142+2610: empty aggregates
    4042                 :         o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
    4043              87 :                      << " || " <<  agg.value() << "->count == 0) {";
    4044              87 :         o->newline(1) << "c->last_error = \"empty aggregate\";";
    4045              87 :         o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
    4046              87 :         o->newline(-1) << "} else";
    4047              87 :         o->newline(1) << "_stp_stat_print_histogram (" << v->hist() << ", " << agg.value() << ");";
    4048              87 :         o->indent(-1);
    4049                 :       }
    4050                 : 
    4051              87 :       delete v;
    4052                 :     }
    4053                 :   else
    4054                 :     {
    4055            4577 :       stmt_expr block(*this);  
    4056                 : 
    4057                 :       // Compute actual arguments
    4058            4577 :       vector<tmpvar> tmp;
    4059                 :       
    4060           14088 :       for (unsigned i=0; i<e->args.size(); i++)
    4061                 :         {
    4062            9511 :           tmpvar t = gensym(e->args[i]->type);
    4063            9511 :           tmp.push_back(t);
    4064                 : 
    4065                 :           // o->newline() << "c->last_stmt = "
    4066                 :           //           << lex_cast_qstring(*e->args[i]->tok) << ";";
    4067                 : 
    4068                 :           // If we've got a numeric or string constant, instead of
    4069                 :           // assigning the numeric or string constant to a temporary,
    4070                 :           // then passing the temporary to _stp_printf/_stp_snprintf,
    4071                 :           // let's just override the temporary with the constant.
    4072            9511 :           if (e->args[i]->tok->type == tok_number
    4073                 :               || e->args[i]->tok->type == tok_string)
    4074             398 :             tmp[i].override(c_expression(e->args[i]));
    4075                 :           else
    4076                 :             c_assign (t.value(), e->args[i],
    4077            9113 :                       "print format actual argument evaluation");       
    4078                 :         }
    4079                 : 
    4080            4577 :       std::vector<print_format::format_component> components;
    4081                 :       
    4082            4577 :       if (e->print_with_format)
    4083                 :         {
    4084            4027 :           components = e->components;
    4085                 :         }
    4086                 :       else
    4087                 :         {
    4088                 :           // Synthesize a print-format string if the user didn't
    4089                 :           // provide one; the synthetic string simply contains one
    4090                 :           // directive for each argument.
    4091            1202 :           for (unsigned i = 0; i < e->args.size(); ++i)
    4092                 :             {
    4093             652 :               if (i > 0 && e->print_with_delim)
    4094              46 :                 components.push_back (e->delimiter);
    4095             652 :               print_format::format_component curr;
    4096             652 :               curr.clear();
    4097             652 :               switch (e->args[i]->type)
    4098                 :                 {
    4099                 :                 case pe_unknown:
    4100               0 :                   throw semantic_error("cannot print unknown expression type", e->args[i]->tok);
    4101                 :                 case pe_stats:
    4102               0 :                   throw semantic_error("cannot print a raw stats object", e->args[i]->tok);
    4103                 :                 case pe_long:
    4104             263 :                   curr.type = print_format::conv_signed_decimal;
    4105             263 :                   break;
    4106                 :                 case pe_string:
    4107             389 :                   curr.type = print_format::conv_string;
    4108                 :                   break;
    4109                 :                 }
    4110             652 :               components.push_back (curr);
    4111                 :             }
    4112                 : 
    4113             550 :           if (e->print_with_newline)
    4114                 :             {
    4115             136 :               print_format::format_component curr;
    4116             136 :               curr.clear();
    4117             136 :               curr.type = print_format::conv_literal;
    4118             136 :               curr.literal_string = "\\n";
    4119             136 :               components.push_back (curr);
    4120                 :             }
    4121                 :         }
    4122                 : 
    4123                 :       // Allocate the result
    4124            4577 :       exp_type ty = e->print_to_stream ? pe_long : pe_string;
    4125            4577 :       tmpvar res = gensym (ty);      
    4126            4577 :       int use_print = 0;
    4127                 : 
    4128            4577 :       string format_string = print_format::components_to_string(components);
    4129            4577 :       if (tmp.size() == 0 || (tmp.size() == 1 && format_string == "%s"))
    4130             669 :         use_print = 1;
    4131            3908 :       else if (tmp.size() == 1 
    4132                 :                && e->args[0]->tok->type == tok_string
    4133                 :                && format_string == "%s\\n")
    4134                 :         {
    4135              92 :           use_print = 1;
    4136              92 :           tmp[0].override(tmp[0].value() + "\"\\n\"");
    4137              92 :           components[0].type = print_format::conv_literal;
    4138                 :         }
    4139                 : 
    4140                 :       // Make the [s]printf call, but not if there was an error evaluating the args
    4141            4577 :       o->newline() << "if (likely (! c->last_error)) {";
    4142            4577 :       o->indent(1);
    4143                 : 
    4144                 :       // Generate code to check that any pointer arguments are actually accessible.  */
    4145            4577 :       int arg_ix = 0;
    4146           22581 :       for (unsigned i = 0; i < components.size(); ++i) {
    4147           18004 :         if (components[i].type == print_format::conv_literal)
    4148            8612 :           continue;
    4149                 : 
    4150                 :         /* Take note of the width and precision arguments, if any.  */
    4151            9392 :         int width_ix = -1, prec_ix= -1;
    4152            9392 :         if (components[i].widthtype == print_format::width_dynamic)
    4153              13 :           width_ix = arg_ix++;
    4154            9392 :         if (components[i].prectype == print_format::prec_dynamic)
    4155              14 :           prec_ix = arg_ix++;
    4156                 : 
    4157                 :         /* Generate a noop call to deref_buffer for %m.  */
    4158            9392 :         if (components[i].type == print_format::conv_memory) {
    4159              17 :           this->probe_or_function_needs_deref_fault_handler = true;
    4160              17 :           o->newline() << "deref_buffer (0, " << tmp[arg_ix].value() << ", ";
    4161              17 :           if (prec_ix == -1)
    4162              11 :             if (width_ix != -1)
    4163               3 :               prec_ix = width_ix;
    4164              17 :           if (prec_ix != -1)
    4165               9 :             o->line() << tmp[prec_ix].value();
    4166                 :           else
    4167               8 :             o->line() << "1";
    4168              17 :           o->line() << ");";
    4169                 :         }
    4170                 : 
    4171            9392 :         ++arg_ix;
    4172                 :       }
    4173                 : 
    4174            4577 :       if (e->print_to_stream)
    4175                 :         {
    4176            3347 :           if (e->print_char)
    4177                 :             {
    4178              14 :               o->newline() << "_stp_print_char (";
    4179              14 :               if (tmp.size())
    4180              14 :                 o->line() << tmp[0].value() << ");";
    4181                 :               else
    4182               0 :                 o->line() << '"' << format_string << "\");";
    4183              14 :               o->newline(-1) << "}";
    4184             768 :               return; 
    4185                 :             }
    4186            3333 :           if (use_print)
    4187                 :             {
    4188             754 :               o->newline() << "_stp_print (";
    4189             754 :               if (tmp.size())
    4190             270 :                 o->line() << tmp[0].value() << ");";
    4191                 :               else
    4192             484 :                 o->line() << '"' << format_string << "\");";
    4193             754 :               o->newline(-1) << "}";
    4194                 :               return;
    4195                 :             }
    4196                 : 
    4197                 :           // We'll just hardcode the result of 0 instead of using the
    4198                 :           // temporary.
    4199            2579 :           res.override("((int64_t)0LL)");
    4200            5158 :           o->newline() << "_stp_printf (";
    4201                 :         }
    4202                 :       else
    4203            1230 :         o->newline() << "_stp_snprintf (" << res.value() << ", MAXSTRINGLEN, ";
    4204                 : 
    4205            3809 :       o->line() << '"' << format_string << '"';
    4206                 :       
    4207                 :       /* Generate the actual arguments. Make sure that they match the expected type of the
    4208                 :          format specifier.  */
    4209            3809 :       arg_ix = 0;
    4210           20953 :       for (unsigned i = 0; i < components.size(); ++i) {
    4211           17144 :         if (components[i].type == print_format::conv_literal)
    4212            7944 :           continue;
    4213                 : 
    4214                 :         /* Cast the width and precision arguments, if any, to 'int'.  */
    4215            9200 :         if (components[i].widthtype == print_format::width_dynamic)
    4216              13 :           o->line() << ", (int)" << tmp[arg_ix++].value();
    4217            9200 :         if (components[i].prectype == print_format::prec_dynamic)
    4218              14 :           o->line() << ", (int)" << tmp[arg_ix++].value();
    4219                 : 
    4220                 :         /* The type of the %m argument is 'char*'.  */
    4221            9200 :         if (components[i].type == print_format::conv_memory)
    4222              17 :           o->line() << ", (char*)(uintptr_t)" << tmp[arg_ix++].value();
    4223                 :         else
    4224            9183 :           o->line() << ", " << tmp[arg_ix++].value();
    4225                 :       }
    4226                 : 
    4227            3809 :       o->line() << ");";
    4228            3809 :       o->newline(-1) << "}";
    4229            3809 :       o->newline() << res.value() << ";";
    4230                 :     }
    4231                 : }
    4232                 : 
    4233                 : 
    4234                 : void 
    4235             205 : c_tmpcounter::visit_stat_op (stat_op* e)
    4236                 : {
    4237             205 :   symbol *sym = get_symbol_within_expression (e->stat);
    4238             205 :   var v = parent->getvar(sym->referent, e->tok);
    4239             204 :   aggvar agg = parent->gensym_aggregate ();
    4240             204 :   tmpvar res = parent->gensym (pe_long);
    4241                 : 
    4242             204 :   agg.declare(*(this->parent));
    4243             204 :   res.declare(*(this->parent));
    4244                 : 
    4245             204 :   if (sym->referent->arity != 0)
    4246                 :     {
    4247                 :       // One temporary per index dimension.
    4248             236 :       for (unsigned i=0; i<sym->referent->index_types.size(); i++)
    4249                 :         {
    4250                 :           // Sorry about this, but with no dynamic_cast<> and no
    4251                 :           // constructor patterns, this is how things work.
    4252             126 :           arrayindex *arr = NULL;
    4253             126 :           if (!expression_is_arrayindex (e->stat, arr))
    4254               0 :             throw semantic_error("expected arrayindex expression in stat_op of array", e->tok);
    4255                 : 
    4256             126 :           tmpvar ix = parent->gensym (sym->referent->index_types[i]);
    4257             126 :           ix.declare (*parent);
    4258             126 :           arr->indexes[i]->visit(this);
    4259                 :         }
    4260             204 :     }
    4261             204 : }
    4262                 : 
    4263                 : void 
    4264             204 : c_unparser::visit_stat_op (stat_op* e)
    4265                 : {
    4266                 :   // Stat ops can be *applied* to two types of expression:
    4267                 :   //
    4268                 :   //  1. An arrayindex expression on a pe_stats-valued array. 
    4269                 :   //
    4270                 :   //  2. A symbol of type pe_stats. 
    4271                 : 
    4272                 :   // FIXME: classify the expression the stat_op is being applied to,
    4273                 :   // call appropriate stp_get_stat() / stp_pmap_get_stat() helper,
    4274                 :   // then reach into resultant struct stat_data.
    4275                 : 
    4276                 :   // FIXME: also note that summarizing anything is expensive, and we
    4277                 :   // really ought to pass a timeout handler into the summary routine,
    4278                 :   // check its response, possibly exit if it ran out of cycles.
    4279                 :   
    4280                 :   {
    4281             204 :     stmt_expr block(*this);
    4282             204 :     symbol *sym = get_symbol_within_expression (e->stat);
    4283             204 :     aggvar agg = gensym_aggregate ();
    4284             204 :     tmpvar res = gensym (pe_long);    
    4285             204 :     var v = getvar(sym->referent, e->tok);
    4286                 :     {
    4287             204 :       if (aggregations_active.count(v.value()))
    4288              78 :         load_aggregate(e->stat, agg, true);
    4289                 :       else
    4290             126 :         load_aggregate(e->stat, agg, false);
    4291                 : 
    4292                 :       // PR 2142+2610: empty aggregates
    4293             204 :       if (e->ctype == sc_count)
    4294                 :         {
    4295              61 :           o->newline() << "if (unlikely (" << agg.value() << " == NULL))";
    4296              61 :           o->indent(1);
    4297              61 :           c_assign(res, "0", e->tok);
    4298              61 :           o->indent(-1);
    4299                 :         }
    4300                 :       else
    4301                 :         {
    4302                 :           o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
    4303             143 :                        << " || " <<  agg.value() << "->count == 0)";
    4304             143 :           o->newline(1) << "c->last_error = \"empty aggregate\";";
    4305             143 :           o->indent(-1);
    4306                 :         }
    4307             204 :       o->newline() << "else";
    4308             204 :       o->indent(1);
    4309             204 :       switch (e->ctype)
    4310                 :         {
    4311                 :         case sc_average:
    4312                 :           c_assign(res, ("_stp_div64(&c->last_error, " + agg.value() + "->sum, "
    4313                 :                          + agg.value() + "->count)"),
    4314              37 :                    e->tok);
    4315              37 :           break;
    4316                 :         case sc_count:
    4317              61 :           c_assign(res, agg.value() + "->count", e->tok);
    4318              61 :           break;
    4319                 :         case sc_sum:
    4320              44 :           c_assign(res, agg.value() + "->sum", e->tok);
    4321              44 :           break;
    4322                 :         case sc_min:
    4323              31 :           c_assign(res, agg.value() + "->min", e->tok);
    4324              31 :           break;
    4325                 :         case sc_max:
    4326              31 :           c_assign(res, agg.value() + "->max", e->tok);
    4327                 :           break;
    4328                 :         }
    4329             204 :       o->indent(-1);
    4330                 :     }    
    4331             204 :     o->newline() << res << ";";
    4332                 :   }
    4333             204 : }
    4334                 : 
    4335                 : 
    4336                 : void 
    4337               0 : c_unparser::visit_hist_op (hist_op*)
    4338                 : {
    4339                 :   // Hist ops can only occur in a limited set of circumstances:
    4340                 :   //
    4341                 :   //  1. Inside an arrayindex expression, as the base referent. See
    4342                 :   //     c_unparser::visit_arrayindex for handling of this case.
    4343                 :   //
    4344                 :   //  2. Inside a foreach statement, as the base referent. See
    4345                 :   //     c_unparser::visit_foreach_loop for handling this case.
    4346                 :   //
    4347                 :   //  3. Inside a print_format expression, as the sole argument. See
    4348                 :   //     c_unparser::visit_print_format for handling this case.
    4349                 :   //
    4350                 :   // Note that none of these cases involves the c_unparser ever
    4351                 :   // visiting this node. We should not get here.
    4352                 : 
    4353               0 :   assert(false);
    4354                 : }
    4355                 : 
    4356                 : int
    4357             283 : emit_symbol_data (systemtap_session& s)
    4358                 : {
    4359             283 :   int rc = 0;
    4360                 : 
    4361                 :   // Instead of processing elf symbol tables, for now we just snatch
    4362                 :   // /proc/kallsyms and convert it to our use.  We need it sorted by
    4363                 :   // address (so we can binary search) , and filtered (to show text
    4364                 :   // symbols only), a task that we defer to grep(1) and sort(1).  It
    4365                 :   // may be useful to cache the symbols.sorted file, perhaps indexed
    4366                 :   // by md5sum(/proc/modules), but let's not until this simple method
    4367                 :   // proves too costly.  LC_ALL=C is already set to avoid the
    4368                 :   // excessive penalty of i18n code in some glibc/coreutils versions.
    4369                 : 
    4370             283 :   string sorted_kallsyms = s.tmpdir + "/symbols.sorted";
    4371             283 :   string sortcmd = "grep \" [AtT] \" /proc/kallsyms | ";
    4372                 :  
    4373             283 :   if (s.symtab == false)
    4374                 :     {
    4375             283 :       s.op->newline() << "/* filled in by runtime */";
    4376             283 :       s.op->newline() << "struct stap_symbol *stap_symbols;";
    4377             283 :       s.op->newline() << "unsigned stap_num_symbols;\n";
    4378             283 :       return 0;
    4379                 :     }
    4380                 : 
    4381               0 :   sortcmd += "sort ";
    4382                 : #if __LP64__
    4383               0 :   sortcmd += "-k 1,16 ";
    4384                 : #else
    4385                 :   sortcmd += "-k 1,8 ";
    4386                 : #endif
    4387               0 :   sortcmd += "-s -o " + sorted_kallsyms;
    4388                 : 
    4389               0 :   if (s.verbose>1) clog << "Running " << sortcmd << endl;
    4390               0 :   rc = system(sortcmd.c_str());
    4391               0 :   if (rc == 0)
    4392                 :     {
    4393               0 :       ifstream kallsyms (sorted_kallsyms.c_str());
    4394                 :       char kallsyms_outbuf [4096];
    4395               0 :       ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
    4396                 :       kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf,
    4397               0 :                                        sizeof(kallsyms_outbuf));
    4398                 :       
    4399               0 :       s.op->newline() << "\n\n#include \"stap-symbols.h\"";
    4400                 : 
    4401               0 :       unsigned i=0;
    4402               0 :       kallsyms_out << "struct stap_symbol _stp_stap_symbols [] = {";
    4403               0 :       string lastaddr;
    4404               0 :       while (! kallsyms.eof())
    4405                 :         {
    4406               0 :           string addr, type, sym, module;
    4407               0 :           kallsyms >> addr >> type >> sym;
    4408               0 :           kallsyms >> ws;
    4409               0 :           if (kallsyms.peek() == '[')
    4410                 :             {
    4411               0 :               string bracketed;
    4412               0 :               kallsyms >> bracketed;
    4413               0 :               module = bracketed.substr (1, bracketed.length()-2);
    4414                 :             }
    4415                 :           
    4416                 :           // NB: kallsyms includes some duplicate addresses
    4417               0 :           if ((type == "t" || type == "T" || type == "A") && lastaddr != addr)
    4418                 :             {
    4419                 :               kallsyms_out << "  { 0x" << addr << ", "
    4420                 :                            << "\"" << sym << "\", "
    4421                 :                            << "\"" << module << "\" },"
    4422               0 :                            << "\n";
    4423               0 :               lastaddr = addr;
    4424               0 :               i ++;
    4425                 :             }
    4426                 :         }
    4427               0 :       kallsyms_out << "};\n";
    4428               0 :       kallsyms_out << "struct stap_symbol *stap_symbols = _stp_stap_symbols;";
    4429               0 :       kallsyms_out << "unsigned stap_num_symbols = " << i << ";\n";
    4430                 :     }
    4431                 : 
    4432               0 :   return rc;
    4433                 : }
    4434                 : 
    4435                 : 
    4436                 : int
    4437             283 : translate_pass (systemtap_session& s)
    4438                 : {
    4439             283 :   int rc = 0;
    4440                 : 
    4441             283 :   s.op = new translator_output (s.translated_source);
    4442             283 :   c_unparser cup (& s);
    4443             283 :   s.up = & cup;
    4444                 : 
    4445                 :   try
    4446                 :     {
    4447                 :       // This is at the very top of the file.
    4448                 :       
    4449                 :       // XXX: the runtime uses #ifdef TEST_MODE to infer systemtap usage.
    4450             283 :       s.op->line() << "#define TEST_MODE 0\n";
    4451                 : 
    4452             283 :       s.op->newline() << "#ifndef MAXNESTING";
    4453             283 :       s.op->newline() << "#define MAXNESTING 10";
    4454             283 :       s.op->newline() << "#endif";
    4455             283 :       s.op->newline() << "#ifndef MAXSTRINGLEN";
    4456             283 :       s.op->newline() << "#define MAXSTRINGLEN 128";
    4457             283 :       s.op->newline() << "#endif";
    4458             283 :       s.op->newline() << "#ifndef MAXACTION";
    4459             283 :       s.op->newline() << "#define MAXACTION 1000";
    4460             283 :       s.op->newline() << "#endif";
    4461             283 :       s.op->newline() << "#ifndef MAXACTION_INTERRUPTIBLE";
    4462             283 :       s.op->newline() << "#define MAXACTION_INTERRUPTIBLE (MAXACTION * 10)";
    4463             283 :       s.op->newline() << "#endif";
    4464             283 :       s.op->newline() << "#ifndef MAXTRYLOCK";
    4465             283 :       s.op->newline() << "#define MAXTRYLOCK MAXACTION";
    4466             283 :       s.op->newline() << "#endif";
    4467             283 :       s.op->newline() << "#ifndef TRYLOCKDELAY";
    4468             283 :       s.op->newline() << "#define TRYLOCKDELAY 100";
    4469             283 :       s.op->newline() << "#endif";
    4470             283 :       s.op->newline() << "#ifndef MAXMAPENTRIES";
    4471             283 :       s.op->newline() << "#define MAXMAPENTRIES 2048";
    4472             283 :       s.op->newline() << "#endif";
    4473             283 :       s.op->newline() << "#ifndef MAXERRORS";
    4474             283 :       s.op->newline() << "#define MAXERRORS 0";
    4475             283 :       s.op->newline() << "#endif";
    4476             283 :       s.op->newline() << "#ifndef MAXSKIPPED";
    4477             283 :       s.op->newline() << "#define MAXSKIPPED 100";
    4478             283 :       s.op->newline() << "#endif";
    4479             283 :       s.op->newline() << "#ifndef MINSTACKSPACE";
    4480             283 :       s.op->newline() << "#define MINSTACKSPACE 1024";
    4481             283 :       s.op->newline() << "#endif";
    4482                 : 
    4483                 :       // Overload processing
    4484             283 :       s.op->newline() << "#ifndef STP_OVERLOAD_INTERVAL";
    4485             283 :       s.op->newline() << "#define STP_OVERLOAD_INTERVAL 1000000000LL";
    4486             283 :       s.op->newline() << "#endif";
    4487             283 :       s.op->newline() << "#ifndef STP_OVERLOAD_THRESHOLD";
    4488             283 :       s.op->newline() << "#define STP_OVERLOAD_THRESHOLD 500000000LL";
    4489             283 :       s.op->newline() << "#endif";
    4490                 :       // We allow the user to completely turn overload processing off
    4491                 :       // (as opposed to tuning it by overriding the values above) by
    4492                 :       // running:  stap -DSTP_NO_OVERLOAD {other options}
    4493             283 :       s.op->newline() << "#ifndef STP_NO_OVERLOAD";
    4494             283 :       s.op->newline() << "#define STP_OVERLOAD";
    4495             283 :       s.op->newline() << "#endif";
    4496                 : 
    4497             283 :       if (s.bulk_mode)
    4498               7 :           s.op->newline() << "#define STP_BULKMODE";
    4499                 :           
    4500             283 :       if (s.timing)
    4501               2 :         s.op->newline() << "#define STP_TIMING";
    4502                 : 
    4503             283 :       if (s.perfmon)
    4504               0 :         s.op->newline() << "#define STP_PERFMON";
    4505                 : 
    4506             283 :       s.op->newline() << "#include \"runtime.h\"";
    4507             283 :       s.op->newline() << "#include \"regs.c\"";
    4508             283 :       s.op->newline() << "#include \"stack.c\"";
    4509             283 :       s.op->newline() << "#include \"regs-ia64.c\"";
    4510             283 :       s.op->newline() << "#include \"stat.c\"";
    4511             283 :       s.op->newline() << "#include <linux/string.h>";
    4512             283 :       s.op->newline() << "#include <linux/timer.h>";
    4513             283 :       s.op->newline() << "#include <linux/delay.h>";
    4514             283 :       s.op->newline() << "#include <linux/profile.h>";
    4515             283 :       s.op->newline() << "#include <linux/random.h>";
    4516             283 :       s.op->newline() << "#include <linux/utsname.h>";
    4517             283 :       s.op->newline() << "#include \"loc2c-runtime.h\" ";
    4518                 :       
    4519                 :       // XXX: old 2.6 kernel hack
    4520             283 :       s.op->newline() << "#ifndef read_trylock";
    4521             283 :       s.op->newline() << "#define read_trylock(x) ({ read_lock(x); 1; })";
    4522             283 :       s.op->newline() << "#endif";
    4523                 : 
    4524             283 :       s.op->newline() << "#if defined(CONFIG_MARKERS)";
    4525             283 :       s.op->newline() << "#include <linux/marker.h>";
    4526             283 :       s.op->newline() << "#endif";
    4527                 : 
    4528             283 :       s.up->emit_common_header (); // context etc.
    4529                 : 
    4530             565 :       for (unsigned i=0; i<s.embeds.size(); i++)
    4531                 :         {
    4532             283 :           s.op->newline() << s.embeds[i]->code << "\n";
    4533                 :         }
    4534                 : 
    4535             282 :       s.op->newline() << "static struct {";
    4536             282 :       s.op->indent(1);
    4537             713 :       for (unsigned i=0; i<s.globals.size(); i++)
    4538                 :         {
    4539             431 :           s.up->emit_global (s.globals[i]);
    4540                 :         }
    4541             282 :       s.op->newline(-1) << "} global = {";
    4542             282 :       s.op->newline(1);
    4543             713 :       for (unsigned i=0; i<s.globals.size(); i++)
    4544                 :         {
    4545             431 :           if (pending_interrupts) return 1;
    4546             431 :           s.up->emit_global_init (s.globals[i]);
    4547                 :         }
    4548             282 :       s.op->newline(-1) << "};";
    4549                 : 
    4550            1524 :       for (unsigned i=0; i<s.functions.size(); i++)
    4551                 :         {
    4552            1242 :           if (pending_interrupts) return 1;
    4553            1242 :           s.op->newline();
    4554            1242 :           s.up->emit_functionsig (s.functions[i]);
    4555                 :         }
    4556                 : 
    4557            1524 :       for (unsigned i=0; i<s.functions.size(); i++)
    4558                 :         {
    4559            1242 :           if (pending_interrupts) return 1;
    4560            1242 :           s.op->newline();
    4561            1242 :           s.up->emit_function (s.functions[i]);
    4562                 :         }
    4563                 : 
    4564                 :       // Run a varuse_collecting_visitor over probes that need global
    4565                 :       // variable locks.  We'll use this information later in
    4566                 :       // emit_locks()/emit_unlocks().
    4567            9537 :       for (unsigned i=0; i<s.probes.size(); i++)
    4568                 :         {
    4569            9255 :         if (pending_interrupts) return 1;
    4570            9255 :         if (s.probes[i]->needs_global_locks())
    4571            8297 :             s.probes[i]->body->visit (&cup.vcv_needs_global_locks);
    4572                 :         }
    4573                 : 
    4574            9536 :       for (unsigned i=0; i<s.probes.size(); i++)
    4575                 :         {
    4576            9255 :           if (pending_interrupts) return 1;
    4577            9255 :           s.up->emit_probe (s.probes[i]);
    4578                 :         }
    4579                 : 
    4580             281 :       s.op->newline();
    4581             281 :       s.up->emit_module_init ();
    4582             281 :       s.op->newline();
    4583             281 :       s.up->emit_module_exit ();
    4584                 : 
    4585             281 :       s.op->newline();
    4586                 : 
    4587                 :       // XXX impedance mismatch
    4588             281 :       s.op->newline() << "int probe_start () {";
    4589             281 :       s.op->newline(1) << "return systemtap_module_init () ? -1 : 0;";
    4590             281 :       s.op->newline(-1) << "}";
    4591             281 :       s.op->newline();
    4592             281 :       s.op->newline() << "void probe_exit () {";
    4593             281 :       s.op->newline(1) << "systemtap_module_exit ();";
    4594             281 :       s.op->newline(-1) << "}";
    4595                 : 
    4596             712 :       for (unsigned i=0; i<s.globals.size(); i++)
    4597                 :         {
    4598             431 :           s.op->newline();
    4599             431 :           s.up->emit_global_param (s.globals[i]);
    4600                 :         }
    4601                 : 
    4602             281 :       s.op->newline() << "MODULE_DESCRIPTION(\"systemtap probe\");";
    4603             281 :       s.op->newline() << "MODULE_LICENSE(\"GPL\");"; // XXX
    4604                 :     }
    4605               4 :   catch (const semantic_error& e)
    4606                 :     {
    4607               2 :       s.print_error (e);
    4608                 :     }
    4609                 : 
    4610             283 :   rc |= emit_symbol_data (s);
    4611                 :   
    4612             283 :   s.op->line() << "\n";
    4613                 : 
    4614             283 :   delete s.op;
    4615             283 :   s.op = 0;
    4616             283 :   s.up = 0;
    4617                 : 
    4618             283 :   return rc + s.num_errors();
    4619            2188 : }

Generated by: LTP GCOV extension version 1.5