]> sourceware.org Git - systemtap.git/commitdiff
Merge branch 'update_visitor'
authorJosh Stone <jistone@redhat.com>
Wed, 11 Feb 2009 04:10:33 +0000 (20:10 -0800)
committerJosh Stone <jistone@redhat.com>
Wed, 11 Feb 2009 04:10:33 +0000 (20:10 -0800)
This brings a new update_visitor that makes it easier to traverse the
parse tree and modify parts of it as necessary.  I wrote this as part of
my in-progress work to allow @cast() expansion, but I was able to apply
it to the dwarf/etc. target variable expanders and to the optimization
stages.  I think the resulting code is more predictable and easier to
follow...

Conflicts:
ChangeLog (bumped my commit dates to push dates...)

ChangeLog
elaborate.cxx
staptree.cxx
staptree.h
tapsets.cxx

index 97fa419b995be4af308868b22432fa618af05ae6..0dc8cdc9fbcee5530675b99cfb945c97c532e7a8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2009-02-10  Josh Stone  <jistone@redhat.com>
+
+       * staptree.h (update_visitor::require): Add a clearok parameter for
+       optimizing traversers to signal that they're ready for NULL back.
+       * elaborate.cxx (dead_assignment_remover): Convert into an
+       update_visitor and remove its now-redundant traversal methods.
+       * elaborate.cxx (dead_stmtexpr_remover): Convert to an update_visitor.
+       * elaborate.cxx (void_statement_reducer): Convert to an update_visitor.
+
+2009-02-10  Josh Stone  <jistone@redhat.com>
+
+       * tapsets.cxx (var_expanding_copy_visitor): This struct becomes
+       var_expanding_visitor and inherits from update_visitor instead of
+       deep_copy_visitor.  Each of the probe-type variants of this are also no
+       longer copiers.
+
+2009-02-10  Josh Stone  <jistone@redhat.com>
+
+       * staptree.h (update_visitor): A new visitor to make it easier to
+       rewrite parts of a probe or function without making a full copy.
+       * staptree.cxx (update_visitor::*): Each child is recursed with a
+       require() call, and then the parent returns itself with provide().
+       * staptree.h (deep_copy_visitor): Inherit from update_visitor to get
+       the recursive descent while updating nodes.
+       * staptree.cxx (deep_copy_visitor::*): Use the implicit copy
+       constructors to copy all fields, then defer to update_visitor for the
+       recursion.  Referents are still cleared from the copies of symbols and
+       function calls.
+
+2009-02-10  Josh Stone  <jistone@redhat.com>
+
+       * staptree.h (require, provide): Simplify stack operations with less
+       pointer magic, and move to be deep_copy_visitor members.
+       * staptree.h (deep_copy_visitor::deep_copy): Templatize
+       * staptree.cxx, tapsets.cxx: Refactor require/provide callers
+
 2009-02-10  Frank Ch. Eigler  <fche@elastic.org>
 
        * tapsets.cxx (find_variable_and_frame_base): Tolerate -1 return
index 5678e8a77853772548d1beb5e46d3ac85ab50cff..ba50defb427eb9b4565ce4ae76a5e87acc90dbca 100644 (file)
@@ -2091,59 +2091,30 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati
 
 // ------------------------------------------------------------------------
 
-struct dead_assignment_remover: public traversing_visitor
+struct dead_assignment_remover: public update_visitor
 {
   systemtap_session& session;
   bool& relaxed_p;
   const varuse_collecting_visitor& vut;
-  expression** current_expr;
 
   dead_assignment_remover(systemtap_session& s, bool& r,
                           const varuse_collecting_visitor& v):
-    session(s), relaxed_p(r), vut(v), current_expr(0) {}
-
-  void visit_expr_statement (expr_statement* s);
-  // XXX: other places where an assignment may be nested should be
-  // handled too (e.g., loop/if conditionals, array indexes, function
-  // parameters).  Until then, they result in visit_assignment() being
-  // called with null current_expr.
+    session(s), relaxed_p(r), vut(v) {}
 
   void visit_assignment (assignment* e);
-  void visit_binary_expression (binary_expression* e);
-  void visit_arrayindex (arrayindex* e);
-  void visit_functioncall (functioncall* e);
-  void visit_if_statement (if_statement* e);
-  void visit_for_loop (for_loop* e);
 };
 
 
-void
-dead_assignment_remover::visit_expr_statement (expr_statement* s)
-{
-  expression** last_expr = current_expr;
-  current_expr = & s->value;
-  s->value->visit (this);
-  s->tok = s->value->tok; // in case it was replaced
-  current_expr = last_expr;
-}
-
-
 void
 dead_assignment_remover::visit_assignment (assignment* e)
 {
+  e->left = require (e->left);
+  e->right = require (e->right);
+
   symbol* left = get_symbol_within_expression (e->left);
   vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target
-  if (current_expr && // see XXX above: this case represents a missed
-                      // optimization opportunity
-      *current_expr == e && // we're not nested any deeper than expected
-      leftvar) // not unresolved $target; intended sideeffect cannot be elided
+  if (leftvar) // not unresolved $target, so intended sideeffect may be elided
     {
-      expression** last_expr = current_expr;
-      e->left->visit (this);
-      current_expr = &e->right;
-      e->right->visit (this);
-      current_expr = last_expr;
-
       if (vut.read.find(leftvar) == vut.read.end()) // var never read?
         {
           // NB: Not so fast!  The left side could be an array whose
@@ -2163,9 +2134,9 @@ dead_assignment_remover::visit_assignment (assignment* e)
                break;
              }
 
-          varuse_collecting_visitor vut;
-          e->left->visit (& vut);
-          if (vut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars
+          varuse_collecting_visitor lvut;
+          e->left->visit (& lvut);
+          if (lvut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars
             {
               /* PR 1119: NB: This is not necessary here.  A write-only
                  variable will also be elided soon at the next _opt2 iteration.
@@ -2178,77 +2149,13 @@ dead_assignment_remover::visit_assignment (assignment* e)
                 clog << "Eliding assignment to " << leftvar->name
                      << " at " << *e->tok << endl;
 
-              *current_expr = e->right; // goodbye assignment*
+              provide (e->right); // goodbye assignment*
               relaxed_p = false;
+              return;
             }
         }
     }
-}
-
-void
-dead_assignment_remover::visit_binary_expression (binary_expression* e)
-{
-  expression** last_expr = current_expr;
-  current_expr = &e->left;
-  e->left->visit (this);
-  current_expr = &e->right;
-  e->right->visit (this);
-  current_expr = last_expr;
-}
-
-void
-dead_assignment_remover::visit_arrayindex (arrayindex *e)
-{
-  symbol *array = NULL;
-  hist_op *hist = NULL;
-  classify_indexable(e->base, array, hist);
-
-  if (array)
-    {
-      expression** last_expr = current_expr;
-      for (unsigned i=0; i < e->indexes.size(); i++)
-       {
-         current_expr = & e->indexes[i];
-         e->indexes[i]->visit (this);
-       }
-      current_expr = last_expr;
-    }
-}
-
-void
-dead_assignment_remover::visit_functioncall (functioncall* e)
-{
-  expression** last_expr = current_expr;
-  for (unsigned i=0; i<e->args.size(); i++)
-    {
-      current_expr = & e->args[i];
-      e->args[i]->visit (this);
-    }
-  current_expr = last_expr;
-}
-
-void
-dead_assignment_remover::visit_if_statement (if_statement* s)
-{
-  expression** last_expr = current_expr;
-  current_expr = & s->condition;
-  s->condition->visit (this);
-  s->thenblock->visit (this);
-  if (s->elseblock)
-    s->elseblock->visit (this);
-  current_expr = last_expr;
-}
-
-void
-dead_assignment_remover::visit_for_loop (for_loop* s)
-{
-  expression** last_expr = current_expr;
-  if (s->init) s->init->visit (this);
-  current_expr = & s->cond;
-  s->cond->visit (this);
-  if (s->incr) s->incr->visit (this);
-  s->block->visit (this);
-  current_expr = last_expr;
+  provide (e);
 }
 
 // Let's remove assignments to variables that are never read.  We
@@ -2268,9 +2175,10 @@ void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
   // This instance may be reused for multiple probe/function body trims.
 
   for (unsigned i=0; i<s.probes.size(); i++)
-    s.probes[i]->body->visit (& dar);
-  for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
-    it->second->body->visit (& dar);
+    s.probes[i]->body = dar.require (s.probes[i]->body);
+  for (map<string,functiondecl*>::iterator it = s.functions.begin();
+       it != s.functions.end(); it++)
+    it->second->body = dar.require (it->second->body);
   // The rewrite operation is performed within the visitor.
 
   // XXX: we could also zap write-only globals here
@@ -2279,15 +2187,14 @@ void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
 
 // ------------------------------------------------------------------------
 
-struct dead_stmtexpr_remover: public traversing_visitor
+struct dead_stmtexpr_remover: public update_visitor
 {
   systemtap_session& session;
   bool& relaxed_p;
-  statement** current_stmt; // pointer to current stmt* being iterated
   set<vardecl*> focal_vars; // vars considered subject to side-effects
 
   dead_stmtexpr_remover(systemtap_session& s, bool& r):
-    session(s), relaxed_p(r), current_stmt(0) {}
+    session(s), relaxed_p(r) {}
 
   void visit_block (block *s);
   void visit_null_statement (null_statement *s);
@@ -2306,7 +2213,8 @@ dead_stmtexpr_remover::visit_null_statement (null_statement *s)
   // easy!
   if (session.verbose>2)
     clog << "Eliding side-effect-free null statement " << *s->tok << endl;
-  *current_stmt = 0;
+  s = 0;
+  provide (s);
 }
 
 
@@ -2316,13 +2224,11 @@ dead_stmtexpr_remover::visit_block (block *s)
   vector<statement*> new_stmts;
   for (unsigned i=0; i<s->statements.size(); i++ )
     {
-      statement** last_stmt = current_stmt;
-      current_stmt = & s->statements[i];
-      s->statements[i]->visit (this);
-      if (*current_stmt != 0)
+      statement* new_stmt = require (s->statements[i], true);
+      if (new_stmt != 0)
         {
           // flatten nested blocks into this one
-          block *b = dynamic_cast<block *>(*current_stmt);
+          block *b = dynamic_cast<block *>(new_stmt);
           if (b)
             {
               if (session.verbose>2)
@@ -2332,42 +2238,32 @@ dead_stmtexpr_remover::visit_block (block *s)
               relaxed_p = false;
             }
           else
-            new_stmts.push_back (*current_stmt);
+            new_stmts.push_back (new_stmt);
         }
-      current_stmt = last_stmt;
     }
   if (new_stmts.size() == 0)
     {
       if (session.verbose>2)
         clog << "Eliding side-effect-free empty block " << *s->tok << endl;
-      *current_stmt = 0;
+      s = 0;
     }
   else if (new_stmts.size() == 1)
     {
       if (session.verbose>2)
         clog << "Eliding side-effect-free singleton block " << *s->tok << endl;
-      *current_stmt = new_stmts[0];
+      provide (new_stmts[0]);
+      return;
     }
   else
-    {
-      s->statements = new_stmts;
-    }
+    s->statements = new_stmts;
+  provide (s);
 }
 
 void
 dead_stmtexpr_remover::visit_if_statement (if_statement *s)
 {
-  statement** last_stmt = current_stmt;
-  current_stmt = & s->thenblock;
-  s->thenblock->visit (this);
-
-  if (s->elseblock)
-    {
-      current_stmt = & s->elseblock;
-      s->elseblock->visit (this);
-      // null *current_stmt is OK here.
-    }
-  current_stmt = last_stmt;
+  s->thenblock = require (s->thenblock, true);
+  s->elseblock = require (s->elseblock, true);
 
   if (s->thenblock == 0)
     {
@@ -2382,7 +2278,7 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s)
               if (session.verbose>2)
                 clog << "Eliding side-effect-free if statement "
                      << *s->tok << endl;
-              *current_stmt = 0; // yeah, baby
+              s = 0; // yeah, baby
             }
           else
             {
@@ -2393,7 +2289,8 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s)
               expr_statement *es = new expr_statement;
               es->value = s->condition;
               es->tok = es->value->tok;
-              *current_stmt = es;
+              provide (es);
+              return;
             }
         }
       else
@@ -2412,31 +2309,27 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s)
           s->elseblock = 0;
         }
     }
+  provide (s);
 }
 
 void
 dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
 {
-  statement** last_stmt = current_stmt;
-  current_stmt = & s->block;
-  s->block->visit (this);
-  current_stmt = last_stmt;
+  s->block = require(s->block, true);
 
   if (s->block == 0)
     {
       if (session.verbose>2)
         clog << "Eliding side-effect-free foreach statement " << *s->tok << endl;
-      *current_stmt = 0; // yeah, baby
+      s = 0; // yeah, baby
     }
+  provide (s);
 }
 
 void
 dead_stmtexpr_remover::visit_for_loop (for_loop *s)
 {
-  statement** last_stmt = current_stmt;
-  current_stmt = & s->block;
-  s->block->visit (this);
-  current_stmt = last_stmt;
+  s->block = require(s->block, true);
 
   if (s->block == 0)
     {
@@ -2450,14 +2343,16 @@ dead_stmtexpr_remover::visit_for_loop (for_loop *s)
         {
           if (session.verbose>2)
             clog << "Eliding side-effect-free for statement " << *s->tok << endl;
-          *current_stmt = 0; // yeah, baby
-          return;
+          s = 0; // yeah, baby
+        }
+      else
+        {
+          // Can't elide this whole statement; put a null in there.
+          s->block = new null_statement();
+          s->block->tok = s->tok;
         }
-
-      // Can't elide this whole statement; put a null in there.
-      s->block = new null_statement();
-      s->block->tok = s->tok;
     }
+  provide (s);
 }
 
 
@@ -2467,8 +2362,7 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
 {
   // Run a varuse query against the operand expression.  If it has no
   // side-effects, replace the entire statement expression by a null
-  // statement.  This replacement is done by overwriting the
-  // current_stmt pointer.
+  // statement with the provide() call.
   //
   // Unlike many other visitors, we do *not* traverse this outermost
   // one into the expression subtrees.  There is no need - no
@@ -2481,8 +2375,7 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
   varuse_collecting_visitor vut;
   s->value->visit (& vut);
 
- if (vut.side_effect_free_wrt (focal_vars) &&
-      *current_stmt == s) // we're not nested any deeper than expected
+  if (vut.side_effect_free_wrt (focal_vars))
     {
       /* PR 1119: NB: this message is not a good idea here.  It can
          name some arbitrary RHS expression of an assignment.
@@ -2497,10 +2390,10 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
 
       // NB: this 0 pointer is invalid to leave around for any length of
       // time, but the parent parse tree objects above handle it.
-      * current_stmt = 0;
-
+      s = 0;
       relaxed_p = false;
     }
+  provide (s);
 }
 
 
@@ -2525,8 +2418,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
       duv.focal_vars.insert (p->locals.begin(),
                              p->locals.end());
 
-      duv.current_stmt = & p->body;
-      p->body->visit (& duv);
+      p->body = duv.require(p->body, true);
       if (p->body == 0)
         {
           if (! s.suppress_warnings)
@@ -2551,8 +2443,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
       duv.focal_vars.insert (s.globals.begin(),
                              s.globals.end());
 
-      duv.current_stmt = & fn->body;
-      fn->body->visit (& duv);
+      fn->body = duv.require(fn->body, true);
       if (fn->body == 0)
         {
           if (! s.suppress_warnings)
@@ -2577,21 +2468,27 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
 // into separate statements that evaluate each subcomponent of the expression.
 // The dead-statement-remover can later remove some parts if they have no side
 // effects.
-struct void_statement_reducer: public traversing_visitor
+//
+// All expressions must be overridden here so we never visit their subexpressions
+// accidentally.  Thus, the only visited expressions should be value of an
+// expr_statement.
+//
+// For an expression to replace its expr_statement with something else, it will
+// let the new statement provide(), and then provide(0) for itself.  The
+// expr_statement will take this as a sign that it's been replaced.
+struct void_statement_reducer: public update_visitor
 {
   systemtap_session& session;
   bool& relaxed_p;
-  statement** current_stmt; // pointer to current stmt* being iterated
-  expr_statement* current_expr; // pointer to current expr being iterated
   set<vardecl*> focal_vars; // vars considered subject to side-effects
 
   void_statement_reducer(systemtap_session& s, bool& r):
-    session(s), relaxed_p(r), current_stmt(0), current_expr(0) {}
+    session(s), relaxed_p(r) {}
 
-  // these just maintain current_stmt while recursing, but don't visit
-  // expressions in the conditional / loop controls.
   void visit_expr_statement (expr_statement* s);
-  void visit_block (block *s);
+
+  // expressions in conditional / loop controls are definitely a side effect,
+  // but still recurse into the child statements
   void visit_if_statement (if_statement* s);
   void visit_for_loop (for_loop* s);
   void visit_foreach_loop (foreach_loop* s);
@@ -2611,72 +2508,54 @@ struct void_statement_reducer: public traversing_visitor
 
   // these are a bit hairy to grok due to the intricacies of indexables and
   // stats, so I'm chickening out and skipping them...
-  void visit_array_in (array_in* e) {}
-  void visit_arrayindex (arrayindex* e) {}
-  void visit_stat_op (stat_op* e) {}
-  void visit_hist_op (hist_op* e) {}
+  void visit_array_in (array_in* e) { provide (e); }
+  void visit_arrayindex (arrayindex* e) { provide (e); }
+  void visit_stat_op (stat_op* e) { provide (e); }
+  void visit_hist_op (hist_op* e) { provide (e); }
 
   // these can't be reduced because they always have an effect
-  void visit_return_statement (return_statement* s) {}
-  void visit_delete_statement (delete_statement* s) {}
-  void visit_pre_crement (pre_crement* e) {}
-  void visit_post_crement (post_crement* e) {}
-  void visit_assignment (assignment* e) {}
+  void visit_return_statement (return_statement* s) { provide (s); }
+  void visit_delete_statement (delete_statement* s) { provide (s); }
+  void visit_pre_crement (pre_crement* e) { provide (e); }
+  void visit_post_crement (post_crement* e) { provide (e); }
+  void visit_assignment (assignment* e) { provide (e); }
 };
 
 
 void
 void_statement_reducer::visit_expr_statement (expr_statement* s)
 {
-  assert(!current_expr); // it shouldn't be possible to have nested expr's
-  current_expr = s;
-  s->value->visit (this);
-  current_expr = NULL;
-}
+  s->value = require (s->value, true);
 
-void
-void_statement_reducer::visit_block (block *s)
-{
-  statement** last_stmt = current_stmt;
-  for (unsigned i=0; i<s->statements.size(); i++ )
-    {
-      current_stmt = & s->statements[i];
-      s->statements[i]->visit (this);
-    }
-  current_stmt = last_stmt;
+  // if the expression provides 0, that's our signal that a new
+  // statement has been provided, so we shouldn't provide this one.
+  if (s->value != 0)
+    provide(s);
 }
 
 void
 void_statement_reducer::visit_if_statement (if_statement* s)
 {
-  statement** last_stmt = current_stmt;
-  current_stmt = & s->thenblock;
-  s->thenblock->visit (this);
-
-  if (s->elseblock)
-    {
-      current_stmt = & s->elseblock;
-      s->elseblock->visit (this);
-    }
-  current_stmt = last_stmt;
+  // s->condition is never void
+  s->thenblock = require (s->thenblock);
+  s->elseblock = require (s->elseblock);
+  provide (s);
 }
 
 void
 void_statement_reducer::visit_for_loop (for_loop* s)
 {
-  statement** last_stmt = current_stmt;
-  current_stmt = & s->block;
-  s->block->visit (this);
-  current_stmt = last_stmt;
+  // s->init/cond/incr are never void
+  s->block = require (s->block);
+  provide (s);
 }
 
 void
 void_statement_reducer::visit_foreach_loop (foreach_loop* s)
 {
-  statement** last_stmt = current_stmt;
-  current_stmt = & s->block;
-  s->block->visit (this);
-  current_stmt = last_stmt;
+  // s->indexes/base/limit are never void
+  s->block = require (s->block);
+  provide (s);
 }
 
 void
@@ -2685,8 +2564,6 @@ void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
   // In void context, the evaluation of "a || b" is exactly like
   // "if (!a) b", so let's do that instead.
 
-  assert(current_expr && current_expr->value == e);
-
   if (session.verbose>2)
     clog << "Creating if statement from unused logical-or "
          << *e->tok << endl;
@@ -2694,8 +2571,6 @@ void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
   if_statement *is = new if_statement;
   is->tok = e->tok;
   is->elseblock = 0;
-  *current_stmt = is;
-  current_expr = NULL;
 
   unary_expression *ue = new unary_expression;
   ue->operand = e->left;
@@ -2710,6 +2585,8 @@ void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
 
   is->visit(this);
   relaxed_p = false;
+  e = 0;
+  provide (e);
 }
 
 void
@@ -2718,8 +2595,6 @@ void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
   // In void context, the evaluation of "a && b" is exactly like
   // "if (a) b", so let's do that instead.
 
-  assert(current_expr && current_expr->value == e);
-
   if (session.verbose>2)
     clog << "Creating if statement from unused logical-and "
          << *e->tok << endl;
@@ -2728,8 +2603,6 @@ void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
   is->tok = e->tok;
   is->elseblock = 0;
   is->condition = e->left;
-  *current_stmt = is;
-  current_expr = NULL;
 
   expr_statement *es = new expr_statement;
   es->value = e->right;
@@ -2738,6 +2611,8 @@ void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
 
   is->visit(this);
   relaxed_p = false;
+  e = 0;
+  provide (e);
 }
 
 void
@@ -2746,8 +2621,6 @@ void_statement_reducer::visit_ternary_expression (ternary_expression* e)
   // In void context, the evaluation of "a ? b : c" is exactly like
   // "if (a) b else c", so let's do that instead.
 
-  assert(current_expr && current_expr->value == e);
-
   if (session.verbose>2)
     clog << "Creating if statement from unused ternary expression "
          << *e->tok << endl;
@@ -2755,8 +2628,6 @@ void_statement_reducer::visit_ternary_expression (ternary_expression* e)
   if_statement *is = new if_statement;
   is->tok = e->tok;
   is->condition = e->cond;
-  *current_stmt = is;
-  current_expr = NULL;
 
   expr_statement *es = new expr_statement;
   es->value = e->truevalue;
@@ -2770,6 +2641,8 @@ void_statement_reducer::visit_ternary_expression (ternary_expression* e)
 
   is->visit(this);
   relaxed_p = false;
+  e = 0;
+  provide (e);
 }
 
 void
@@ -2778,15 +2651,11 @@ void_statement_reducer::visit_binary_expression (binary_expression* e)
   // When the result of a binary operation isn't needed, it's just as good to
   // evaluate the operands as sequential statements in a block.
 
-  assert(current_expr && current_expr->value == e);
-
   if (session.verbose>2)
     clog << "Eliding unused binary " << *e->tok << endl;
 
   block *b = new block;
-  b->tok = current_expr->tok;
-  *current_stmt = b;
-  current_expr = NULL;
+  b->tok = e->tok;
 
   expr_statement *es = new expr_statement;
   es->value = e->left;
@@ -2800,6 +2669,8 @@ void_statement_reducer::visit_binary_expression (binary_expression* e)
 
   b->visit(this);
   relaxed_p = false;
+  e = 0;
+  provide (e);
 }
 
 void
@@ -2808,16 +2679,11 @@ void_statement_reducer::visit_unary_expression (unary_expression* e)
   // When the result of a unary operation isn't needed, it's just as good to
   // evaluate the operand directly
 
-  assert(current_expr && current_expr->value == e);
-
   if (session.verbose>2)
     clog << "Eliding unused unary " << *e->tok << endl;
 
-  current_expr->value = e->operand;
-  current_expr->tok = current_expr->value->tok;
-  current_expr->value->visit(this);
-
   relaxed_p = false;
+  e->operand->visit(this);
 }
 
 void
@@ -2839,24 +2705,26 @@ void_statement_reducer::visit_functioncall (functioncall* e)
   // and just evaluate the arguments in sequence
 
   if (!e->args.size())
-    return;
+    {
+      provide (e);
+      return;
+    }
 
   varuse_collecting_visitor vut;
   vut.traversed.insert (e->referent);
   vut.current_function = e->referent;
   e->referent->body->visit (& vut);
   if (!vut.side_effect_free_wrt (focal_vars))
-    return;
-
-  assert(current_expr && current_expr->value == e);
+    {
+      provide (e);
+      return;
+    }
 
   if (session.verbose>2)
     clog << "Eliding side-effect-free function call " << *e->tok << endl;
 
   block *b = new block;
   b->tok = e->tok;
-  *current_stmt = b;
-  current_expr = NULL;
 
   for (unsigned i=0; i<e->args.size(); i++ )
     {
@@ -2868,6 +2736,8 @@ void_statement_reducer::visit_functioncall (functioncall* e)
 
   b->visit(this);
   relaxed_p = false;
+  e = 0;
+  provide (e);
 }
 
 void
@@ -2877,17 +2747,16 @@ void_statement_reducer::visit_print_format (print_format* e)
   // arguments in sequence
 
   if (e->print_to_stream || !e->args.size())
-    return;
-
-  assert(current_expr && current_expr->value == e);
+    {
+      provide (e);
+      return;
+    }
 
   if (session.verbose>2)
     clog << "Eliding unused print " << *e->tok << endl;
 
   block *b = new block;
   b->tok = e->tok;
-  *current_stmt = b;
-  current_expr = NULL;
 
   for (unsigned i=0; i<e->args.size(); i++ )
     {
@@ -2899,6 +2768,8 @@ void_statement_reducer::visit_print_format (print_format* e)
 
   b->visit(this);
   relaxed_p = false;
+  e = 0;
+  provide (e);
 }
 
 
@@ -2912,17 +2783,10 @@ void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
   vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
 
   for (unsigned i=0; i<s.probes.size(); i++)
-    {
-      derived_probe* p = s.probes[i];
-      vuv.current_stmt = & p->body;
-      p->body->visit (& vuv);
-    }
-  for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
-    {
-      functiondecl* fn = it->second;
-      vuv.current_stmt = & fn->body;
-      fn->body->visit (& vuv);
-    }
+    s.probes[i]->body = vuv.require (s.probes[i]->body);
+  for (map<string,functiondecl*>::iterator it = s.functions.begin();
+       it != s.functions.end(); it++)
+    it->second->body = vuv.require (it->second->body);
 }
 
 
index cc61811188581d74fb1581314f516737e140c48c..9ffbaf0909df5fd2ae6bc20a9cd9eb3fffa9c7a6 100644 (file)
@@ -2098,414 +2098,465 @@ throwing_visitor::visit_hist_op (hist_op* e)
 
 
 void
-deep_copy_visitor::visit_block (block* s)
+update_visitor::visit_block (block* s)
 {
-  block* n = new block;
-  n->tok = s->tok;
   for (unsigned i = 0; i < s->statements.size(); ++i)
+    s->statements[i] = require (s->statements[i]);
+  provide (s);
+}
+
+void
+update_visitor::visit_embeddedcode (embeddedcode* s)
+{
+  provide (s);
+}
+
+void
+update_visitor::visit_null_statement (null_statement* s)
+{
+  provide (s);
+}
+
+void
+update_visitor::visit_expr_statement (expr_statement* s)
+{
+  s->value = require (s->value);
+  provide (s);
+}
+
+void
+update_visitor::visit_if_statement (if_statement* s)
+{
+  s->condition = require (s->condition);
+  s->thenblock = require (s->thenblock);
+  s->elseblock = require (s->elseblock);
+  provide (s);
+}
+
+void
+update_visitor::visit_for_loop (for_loop* s)
+{
+  s->init = require (s->init);
+  s->cond = require (s->cond);
+  s->incr = require (s->incr);
+  s->block = require (s->block);
+  provide (s);
+}
+
+void
+update_visitor::visit_foreach_loop (foreach_loop* s)
+{
+  for (unsigned i = 0; i < s->indexes.size(); ++i)
+    s->indexes[i] = require (s->indexes[i]);
+  s->base = require (s->base);
+  s->limit = require (s->limit);
+  s->block = require (s->block);
+  provide (s);
+}
+
+void
+update_visitor::visit_return_statement (return_statement* s)
+{
+  s->value = require (s->value);
+  provide (s);
+}
+
+void
+update_visitor::visit_delete_statement (delete_statement* s)
+{
+  s->value = require (s->value);
+  provide (s);
+}
+
+void
+update_visitor::visit_next_statement (next_statement* s)
+{
+  provide (s);
+}
+
+void
+update_visitor::visit_break_statement (break_statement* s)
+{
+  provide (s);
+}
+
+void
+update_visitor::visit_continue_statement (continue_statement* s)
+{
+  provide (s);
+}
+
+void
+update_visitor::visit_literal_string (literal_string* e)
+{
+  provide (e);
+}
+
+void
+update_visitor::visit_literal_number (literal_number* e)
+{
+  provide (e);
+}
+
+void
+update_visitor::visit_binary_expression (binary_expression* e)
+{
+  e->left = require (e->left);
+  e->right = require (e->right);
+  provide (e);
+}
+
+void
+update_visitor::visit_unary_expression (unary_expression* e)
+{
+  e->operand = require (e->operand);
+  provide (e);
+}
+
+void
+update_visitor::visit_pre_crement (pre_crement* e)
+{
+  e->operand = require (e->operand);
+  provide (e);
+}
+
+void
+update_visitor::visit_post_crement (post_crement* e)
+{
+  e->operand = require (e->operand);
+  provide (e);
+}
+
+
+void
+update_visitor::visit_logical_or_expr (logical_or_expr* e)
+{
+  e->left = require (e->left);
+  e->right = require (e->right);
+  provide (e);
+}
+
+void
+update_visitor::visit_logical_and_expr (logical_and_expr* e)
+{
+  e->left = require (e->left);
+  e->right = require (e->right);
+  provide (e);
+}
+
+void
+update_visitor::visit_array_in (array_in* e)
+{
+  e->operand = require (e->operand);
+  provide (e);
+}
+
+void
+update_visitor::visit_comparison (comparison* e)
+{
+  e->left = require (e->left);
+  e->right = require (e->right);
+  provide (e);
+}
+
+void
+update_visitor::visit_concatenation (concatenation* e)
+{
+  e->left = require (e->left);
+  e->right = require (e->right);
+  provide (e);
+}
+
+void
+update_visitor::visit_ternary_expression (ternary_expression* e)
+{
+  e->cond = require (e->cond);
+  e->truevalue = require (e->truevalue);
+  e->falsevalue = require (e->falsevalue);
+  provide (e);
+}
+
+void
+update_visitor::visit_assignment (assignment* e)
+{
+  e->left = require (e->left);
+  e->right = require (e->right);
+  provide (e);
+}
+
+void
+update_visitor::visit_symbol (symbol* e)
+{
+  provide (e);
+}
+
+void
+update_visitor::visit_target_symbol (target_symbol* e)
+{
+  provide (e);
+}
+
+void
+update_visitor::visit_arrayindex (arrayindex* e)
+{
+  e->base = require (e->base);
+  for (unsigned i = 0; i < e->indexes.size(); ++i)
+    e->indexes[i] = require (e->indexes[i]);
+  provide (e);
+}
+
+void
+update_visitor::visit_functioncall (functioncall* e)
+{
+  for (unsigned i = 0; i < e->args.size(); ++i)
+    e->args[i] = require (e->args[i]);
+  provide (e);
+}
+
+void
+update_visitor::visit_print_format (print_format* e)
+{
+  for (unsigned i = 0; i < e->args.size(); ++i)
+    e->args[i] = require (e->args[i]);
+  e->hist = require (e->hist);
+  provide (e);
+}
+
+void
+update_visitor::visit_stat_op (stat_op* e)
+{
+  e->stat = require (e->stat);
+  provide (e);
+}
+
+void
+update_visitor::visit_hist_op (hist_op* e)
+{
+  e->stat = require (e->stat);
+  provide (e);
+}
+
+template <> indexable*
+update_visitor::require <indexable*> (indexable* src, bool clearok)
+{
+  indexable *dst = NULL;
+  if (src != NULL)
     {
-      statement* ns;
-      require <statement*> (this, &ns, s->statements[i]);
-      n->statements.push_back(ns);
+      symbol *array_src=NULL;
+      hist_op *hist_src=NULL;
+
+      classify_indexable(src, array_src, hist_src);
+
+      if (array_src)
+        dst = require (array_src);
+      else
+        dst = require (hist_src);
+      assert(clearok || dst);
     }
-  provide <block*> (this, n);
+  return dst;
+}
+
+
+// ------------------------------------------------------------------------
+
+
+void
+deep_copy_visitor::visit_block (block* s)
+{
+  update_visitor::visit_block(new block(*s));
 }
 
 void
 deep_copy_visitor::visit_embeddedcode (embeddedcode* s)
 {
-  embeddedcode* n = new embeddedcode;
-  n->tok = s->tok;
-  n->code = s->code;
-  provide <embeddedcode*> (this, n);
+  update_visitor::visit_embeddedcode(new embeddedcode(*s));
 }
 
 void
 deep_copy_visitor::visit_null_statement (null_statement* s)
 {
-  null_statement* n = new null_statement;
-  n->tok = s->tok;
-  provide <null_statement*> (this, n);
+  update_visitor::visit_null_statement(new null_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_expr_statement (expr_statement* s)
 {
-  expr_statement* n = new expr_statement;
-  n->tok = s->tok;
-  require <expression*> (this, &(n->value), s->value);
-  provide <expr_statement*> (this, n);
+  update_visitor::visit_expr_statement(new expr_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_if_statement (if_statement* s)
 {
-  if_statement* n = new if_statement;
-  n->tok = s->tok;
-  require <expression*> (this, &(n->condition), s->condition);
-  require <statement*> (this, &(n->thenblock), s->thenblock);
-  require <statement*> (this, &(n->elseblock), s->elseblock);
-  provide <if_statement*> (this, n);
+  update_visitor::visit_if_statement(new if_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_for_loop (for_loop* s)
 {
-  for_loop* n = new for_loop;
-  n->tok = s->tok;
-  require <expr_statement*> (this, &(n->init), s->init);
-  require <expression*> (this, &(n->cond), s->cond);
-  require <expr_statement*> (this, &(n->incr), s->incr);
-  require <statement*> (this, &(n->block), s->block);
-  provide <for_loop*> (this, n);
+  update_visitor::visit_for_loop(new for_loop(*s));
 }
 
 void
 deep_copy_visitor::visit_foreach_loop (foreach_loop* s)
 {
-  foreach_loop* n = new foreach_loop;
-  n->tok = s->tok;
-  for (unsigned i = 0; i < s->indexes.size(); ++i)
-    {
-      symbol* sym;
-      require <symbol*> (this, &sym, s->indexes[i]);
-      n->indexes.push_back(sym);
-    }
-
-  require <indexable*> (this, &(n->base), s->base);
-
-  n->sort_direction = s->sort_direction;
-  n->sort_column = s->sort_column;
-  require <expression*> (this, &(n->limit), s->limit);
-
-  require <statement*> (this, &(n->block), s->block);
-  provide <foreach_loop*> (this, n);
+  update_visitor::visit_foreach_loop(new foreach_loop(*s));
 }
 
 void
 deep_copy_visitor::visit_return_statement (return_statement* s)
 {
-  return_statement* n = new return_statement;
-  n->tok = s->tok;
-  require <expression*> (this, &(n->value), s->value);
-  provide <return_statement*> (this, n);
+  update_visitor::visit_return_statement(new return_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_delete_statement (delete_statement* s)
 {
-  delete_statement* n = new delete_statement;
-  n->tok = s->tok;
-  require <expression*> (this, &(n->value), s->value);
-  provide <delete_statement*> (this, n);
+  update_visitor::visit_delete_statement(new delete_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_next_statement (next_statement* s)
 {
-  next_statement* n = new next_statement;
-  n->tok = s->tok;
-  provide <next_statement*> (this, n);
+  update_visitor::visit_next_statement(new next_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_break_statement (break_statement* s)
 {
-  break_statement* n = new break_statement;
-  n->tok = s->tok;
-  provide <break_statement*> (this, n);
+  update_visitor::visit_break_statement(new break_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_continue_statement (continue_statement* s)
 {
-  continue_statement* n = new continue_statement;
-  n->tok = s->tok;
-  provide <continue_statement*> (this, n);
+  update_visitor::visit_continue_statement(new continue_statement(*s));
 }
 
 void
 deep_copy_visitor::visit_literal_string (literal_string* e)
 {
-  literal_string* n = new literal_string(e->value);
-  n->tok = e->tok;
-  provide <literal_string*> (this, n);
+  update_visitor::visit_literal_string(new literal_string(*e));
 }
 
 void
 deep_copy_visitor::visit_literal_number (literal_number* e)
 {
-  literal_number* n = new literal_number(e->value);
-  n->tok = e->tok;
-  provide <literal_number*> (this, n);
+  update_visitor::visit_literal_number(new literal_number(*e));
 }
 
 void
 deep_copy_visitor::visit_binary_expression (binary_expression* e)
 {
-  binary_expression* n = new binary_expression;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->left), e->left);
-  require <expression*> (this, &(n->right), e->right);
-  provide <binary_expression*> (this, n);
+  update_visitor::visit_binary_expression(new binary_expression(*e));
 }
 
 void
 deep_copy_visitor::visit_unary_expression (unary_expression* e)
 {
-  unary_expression* n = new unary_expression;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->operand), e->operand);
-  provide <unary_expression*> (this, n);
+  update_visitor::visit_unary_expression(new unary_expression(*e));
 }
 
 void
 deep_copy_visitor::visit_pre_crement (pre_crement* e)
 {
-  pre_crement* n = new pre_crement;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->operand), e->operand);
-  provide <pre_crement*> (this, n);
+  update_visitor::visit_pre_crement(new pre_crement(*e));
 }
 
 void
 deep_copy_visitor::visit_post_crement (post_crement* e)
 {
-  post_crement* n = new post_crement;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->operand), e->operand);
-  provide <post_crement*> (this, n);
+  update_visitor::visit_post_crement(new post_crement(*e));
 }
 
 
 void
 deep_copy_visitor::visit_logical_or_expr (logical_or_expr* e)
 {
-  logical_or_expr* n = new logical_or_expr;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->left), e->left);
-  require <expression*> (this, &(n->right), e->right);
-  provide <logical_or_expr*> (this, n);
+  update_visitor::visit_logical_or_expr(new logical_or_expr(*e));
 }
 
 void
 deep_copy_visitor::visit_logical_and_expr (logical_and_expr* e)
 {
-  logical_and_expr* n = new logical_and_expr;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->left), e->left);
-  require <expression*> (this, &(n->right), e->right);
-  provide <logical_and_expr*> (this, n);
+  update_visitor::visit_logical_and_expr(new logical_and_expr(*e));
 }
 
 void
 deep_copy_visitor::visit_array_in (array_in* e)
 {
-  array_in* n = new array_in;
-  n->tok = e->tok;
-  require <arrayindex*> (this, &(n->operand), e->operand);
-  provide <array_in*> (this, n);
+  update_visitor::visit_array_in(new array_in(*e));
 }
 
 void
 deep_copy_visitor::visit_comparison (comparison* e)
 {
-  comparison* n = new comparison;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->left), e->left);
-  require <expression*> (this, &(n->right), e->right);
-  provide <comparison*> (this, n);
+  update_visitor::visit_comparison(new comparison(*e));
 }
 
 void
 deep_copy_visitor::visit_concatenation (concatenation* e)
 {
-  concatenation* n = new concatenation;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->left), e->left);
-  require <expression*> (this, &(n->right), e->right);
-  provide <concatenation*> (this, n);
+  update_visitor::visit_concatenation(new concatenation(*e));
 }
 
 void
 deep_copy_visitor::visit_ternary_expression (ternary_expression* e)
 {
-  ternary_expression* n = new ternary_expression;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->cond), e->cond);
-  require <expression*> (this, &(n->truevalue), e->truevalue);
-  require <expression*> (this, &(n->falsevalue), e->falsevalue);
-  provide <ternary_expression*> (this, n);
+  update_visitor::visit_ternary_expression(new ternary_expression(*e));
 }
 
 void
 deep_copy_visitor::visit_assignment (assignment* e)
 {
-  assignment* n = new assignment;
-  n->op = e->op;
-  n->tok = e->tok;
-  require <expression*> (this, &(n->left), e->left);
-  require <expression*> (this, &(n->right), e->right);
-  provide <assignment*> (this, n);
+  update_visitor::visit_assignment(new assignment(*e));
 }
 
 void
 deep_copy_visitor::visit_symbol (symbol* e)
 {
-  symbol* n = new symbol;
-  n->tok = e->tok;
-  n->name = e->name;
-  n->referent = NULL;
-  provide <symbol*> (this, n);
+  symbol* n = new symbol(*e);
+  n->referent = NULL; // don't copy!
+  update_visitor::visit_symbol(n);
 }
 
 void
 deep_copy_visitor::visit_target_symbol (target_symbol* e)
 {
-  target_symbol* n = new target_symbol;
-  n->tok = e->tok;
-  n->base_name = e->base_name;
-  n->components = e->components;
-  provide <target_symbol*> (this, n);
+  target_symbol* n = new target_symbol(*e);
+  n->referent = NULL; // don't copy!
+  update_visitor::visit_target_symbol(n);
 }
 
 void
 deep_copy_visitor::visit_arrayindex (arrayindex* e)
 {
-  arrayindex* n = new arrayindex;
-  n->tok = e->tok;
-
-  require <indexable*> (this, &(n->base), e->base);
-
-  for (unsigned i = 0; i < e->indexes.size(); ++i)
-    {
-      expression* ne;
-      require <expression*> (this, &ne, e->indexes[i]);
-      n->indexes.push_back(ne);
-    }
-  provide <arrayindex*> (this, n);
+  update_visitor::visit_arrayindex(new arrayindex(*e));
 }
 
 void
 deep_copy_visitor::visit_functioncall (functioncall* e)
 {
-  functioncall* n = new functioncall;
-  n->tok = e->tok;
-  n->function = e->function;
-  n->referent = NULL;
-  for (unsigned i = 0; i < e->args.size(); ++i)
-    {
-      expression* na;
-      require <expression*> (this, &na, e->args[i]);
-      n->args.push_back(na);
-    }
-  provide <functioncall*> (this, n);
+  functioncall* n = new functioncall(*e);
+  n->referent = NULL; // don't copy!
+  update_visitor::visit_functioncall(n);
 }
 
 void
 deep_copy_visitor::visit_print_format (print_format* e)
 {
-  print_format* n = new print_format;
-  n->tok = e->tok;
-  n->print_to_stream = e->print_to_stream;
-  n->print_with_format = e->print_with_format;
-  n->print_with_delim = e->print_with_delim;
-  n->print_with_newline = e->print_with_newline;
-  n->print_char = e->print_char;
-  n->raw_components = e->raw_components;
-  n->components = e->components;
-  n->delimiter = e->delimiter;
-  for (unsigned i = 0; i < e->args.size(); ++i)
-    {
-      expression* na;
-      require <expression*> (this, &na, e->args[i]);
-      n->args.push_back(na);
-    }
-  if (e->hist)
-    require <hist_op*> (this, &n->hist, e->hist);
-  provide <print_format*> (this, n);
+  update_visitor::visit_print_format(new print_format(*e));
 }
 
 void
 deep_copy_visitor::visit_stat_op (stat_op* e)
 {
-  stat_op* n = new stat_op;
-  n->tok = e->tok;
-  n->ctype = e->ctype;
-  require <expression*> (this, &(n->stat), e->stat);
-  provide <stat_op*> (this, n);
+  update_visitor::visit_stat_op(new stat_op(*e));
 }
 
 void
 deep_copy_visitor::visit_hist_op (hist_op* e)
 {
-  hist_op* n = new hist_op;
-  n->tok = e->tok;
-  n->htype = e->htype;
-  n->params = e->params;
-  require <expression*> (this, &(n->stat), e->stat);
-  provide <hist_op*> (this, n);
-}
-
-block*
-deep_copy_visitor::deep_copy (block* b)
-{
-  block* n;
-  deep_copy_visitor v;
-  require <block*> (&v, &n, b);
-  return n;
-}
-
-statement*
-deep_copy_visitor::deep_copy (statement* s)
-{
-  statement* n;
-  deep_copy_visitor v;
-  require <statement*> (&v, &n, s);
-  return n;
-}
-
-expression*
-deep_copy_visitor::deep_copy (expression* s)
-{
-  expression* n;
-  deep_copy_visitor v;
-  require <expression*> (&v, &n, s);
-  return n;
-}
-
-template <> void
-require <indexable *> (deep_copy_visitor* v, indexable** dst, indexable* src)
-{
-  if (src != NULL)
-    {
-      symbol *array_src=NULL, *array_dst=NULL;
-      hist_op *hist_src=NULL, *hist_dst=NULL;
-
-      classify_indexable(src, array_src, hist_src);
-
-      *dst = NULL;
-
-      if (array_src)
-       {
-         require <symbol*> (v, &array_dst, array_src);
-         *dst = array_dst;
-       }
-      else
-       {
-         require <hist_op*> (v, &hist_dst, hist_src);
-         *dst = hist_dst;
-       }
-      assert (*dst);
-    }
+  update_visitor::visit_hist_op(new hist_op(*e));
 }
 
 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
index 8c37776f3e1e3d69707d168fa7fd2f2bda7ef5ff..0cd0ee0d581fd62d8223d3e86ba74704179f4e1f 100644 (file)
@@ -810,19 +810,31 @@ struct throwing_visitor: public visitor
   void visit_hist_op (hist_op* e);
 };
 
-// A visitor which performs a deep copy of the root node it's applied
-// to. NB: It does not copy any of the variable or function
-// declarations; those fields are set to NULL, assuming you want to
-// re-infer the declarations in a new context (the one you're copying
-// to).
+// A visitor similar to a traversing_visitor, but with the ability to rewrite
+// parts of the tree through require/provide.
 
-struct deep_copy_visitor: public visitor
+struct update_visitor: public visitor
 {
-  std::stack<void *> targets;
+  template <typename T> T require (T src, bool clearok=false)
+  {
+    T dst = NULL;
+    if (src != NULL)
+      {
+        src->visit(this);
+        assert(!targets.empty());
+        dst = static_cast<T>(targets.top());
+        targets.pop();
+        assert(clearok || dst);
+      }
+    return dst;
+  }
+
+  template <typename T> void provide (T src)
+  {
+    targets.push(static_cast<void*>(src));
+  }
 
-  static expression *deep_copy (expression *s);
-  static statement *deep_copy (statement *s);
-  static block *deep_copy (block *s);
+  virtual ~update_visitor() { assert(targets.empty()); }
 
   virtual void visit_block (block *s);
   virtual void visit_embeddedcode (embeddedcode *s);
@@ -856,30 +868,61 @@ struct deep_copy_visitor: public visitor
   virtual void visit_print_format (print_format* e);
   virtual void visit_stat_op (stat_op* e);
   virtual void visit_hist_op (hist_op* e);
+
+private:
+  std::stack<void *> targets;
 };
 
-template <typename T> void
-require (deep_copy_visitor* v, T* dst, T src)
-{
-  *dst = NULL;
-  if (src != NULL)
-    {
-      v->targets.push(static_cast<void* >(dst));
-      src->visit(v);
-      v->targets.pop();
-      assert(*dst);
-    }
-}
+template <> indexable*
+update_visitor::require <indexable*> (indexable* src, bool clearok);
 
-template <> void
-require <indexable *> (deep_copy_visitor* v, indexable** dst, indexable* src);
+// A visitor which performs a deep copy of the root node it's applied
+// to. NB: It does not copy any of the variable or function
+// declarations; those fields are set to NULL, assuming you want to
+// re-infer the declarations in a new context (the one you're copying
+// to).
 
-template <typename T> void
-provide (deep_copy_visitor* v, T src)
+struct deep_copy_visitor: public update_visitor
 {
-  assert(!v->targets.empty());
-  *(static_cast<T*>(v->targets.top())) = src;
-}
+  template <typename T> static T deep_copy (T e)
+  {
+    deep_copy_visitor v;
+    return v.require (e);
+  }
+
+  virtual void visit_block (block *s);
+  virtual void visit_embeddedcode (embeddedcode *s);
+  virtual void visit_null_statement (null_statement *s);
+  virtual void visit_expr_statement (expr_statement *s);
+  virtual void visit_if_statement (if_statement* s);
+  virtual void visit_for_loop (for_loop* s);
+  virtual void visit_foreach_loop (foreach_loop* s);
+  virtual void visit_return_statement (return_statement* s);
+  virtual void visit_delete_statement (delete_statement* s);
+  virtual void visit_next_statement (next_statement* s);
+  virtual void visit_break_statement (break_statement* s);
+  virtual void visit_continue_statement (continue_statement* s);
+  virtual void visit_literal_string (literal_string* e);
+  virtual void visit_literal_number (literal_number* e);
+  virtual void visit_binary_expression (binary_expression* e);
+  virtual void visit_unary_expression (unary_expression* e);
+  virtual void visit_pre_crement (pre_crement* e);
+  virtual void visit_post_crement (post_crement* e);
+  virtual void visit_logical_or_expr (logical_or_expr* e);
+  virtual void visit_logical_and_expr (logical_and_expr* e);
+  virtual void visit_array_in (array_in* e);
+  virtual void visit_comparison (comparison* e);
+  virtual void visit_concatenation (concatenation* e);
+  virtual void visit_ternary_expression (ternary_expression* e);
+  virtual void visit_assignment (assignment* e);
+  virtual void visit_symbol (symbol* e);
+  virtual void visit_target_symbol (target_symbol* e);
+  virtual void visit_arrayindex (arrayindex* e);
+  virtual void visit_functioncall (functioncall* e);
+  virtual void visit_print_format (print_format* e);
+  virtual void visit_stat_op (stat_op* e);
+  virtual void visit_hist_op (hist_op* e);
+};
 
 #endif // STAPTREE_H
 
index 615ba07b03f9b0441ad25a24a554483ab699cce6..d479efda3f1a7ceb0968d20166238e78e26b013d 100644 (file)
@@ -4205,17 +4205,17 @@ dwflpp::query_modules(dwarf_query *q)
   iterate_over_modules(&query_module, q);
 }
 
-struct var_expanding_copy_visitor: public deep_copy_visitor
+struct var_expanding_visitor: public update_visitor
 {
   static unsigned tick;
   stack<functioncall**> target_symbol_setter_functioncalls;
 
-  var_expanding_copy_visitor() {}
+  var_expanding_visitor() {}
   void visit_assignment (assignment* e);
 };
 
 
-struct dwarf_var_expanding_copy_visitor: public var_expanding_copy_visitor
+struct dwarf_var_expanding_visitor: public var_expanding_visitor
 {
   dwarf_query & q;
   Dwarf_Die *scope_die;
@@ -4225,17 +4225,17 @@ struct dwarf_var_expanding_copy_visitor: public var_expanding_copy_visitor
   std::map<std::string, symbol *> return_ts_map;
   bool visited;
 
-  dwarf_var_expanding_copy_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a):
+  dwarf_var_expanding_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a):
     q(q), scope_die(sd), addr(a), add_block(NULL), add_probe(NULL), visited(false) {}
   void visit_target_symbol (target_symbol* e);
 };
 
 
 
-unsigned var_expanding_copy_visitor::tick = 0;
+unsigned var_expanding_visitor::tick = 0;
 
 void
-var_expanding_copy_visitor::visit_assignment (assignment* e)
+var_expanding_visitor::visit_assignment (assignment* e)
 {
   // Our job would normally be to require() the left and right sides
   // into a new assignment. What we're doing is slightly trickier:
@@ -4253,9 +4253,9 @@ var_expanding_copy_visitor::visit_assignment (assignment* e)
   expression *new_left, *new_right;
 
   target_symbol_setter_functioncalls.push (&fcall);
-  require<expression*> (this, &new_left, e->left);
+  new_left = require (e->left);
   target_symbol_setter_functioncalls.pop ();
-  require<expression*> (this, &new_right, e->right);
+  new_right = require (e->right);
 
   if (fcall != NULL)
     {
@@ -4263,7 +4263,7 @@ var_expanding_copy_visitor::visit_assignment (assignment* e)
       // and it has been replaced with a set_target_foo() function
       // call; we are going to provide that function call -- with the
       // right child spliced in as sole argument -- in place of
-      // ourselves, in the deep copy we're in the middle of making.
+      // ourselves, in the var expansion we're in the middle of making.
 
       // FIXME: for the time being, we only support plan $foo = bar,
       // not += or any other op= variant. This is fixable, but a bit
@@ -4274,22 +4274,19 @@ var_expanding_copy_visitor::visit_assignment (assignment* e)
 
       assert (new_left == fcall);
       fcall->args.push_back (new_right);
-      provide <expression*> (this, fcall);
+      provide (fcall);
     }
   else
     {
-      assignment* n = new assignment;
-      n->op = e->op;
-      n->tok = e->tok;
-      n->left = new_left;
-      n->right = new_right;
-      provide <assignment*> (this, n);
+      e->left = new_left;
+      e->right = new_right;
+      provide (e);
     }
 }
 
 
 void
-dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
+dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
 {
   assert(e->base_name.size() > 0 && e->base_name[0] == '$');
   visited = true;
@@ -4318,7 +4315,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
       map<string, symbol *>::iterator i = return_ts_map.find(ts_name);
       if (i != return_ts_map.end())
        {
-         provide <symbol*> (this, i->second);
+         provide (i->second);
          return;
        }
 
@@ -4576,7 +4573,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
       // (4) Provide the '_dwarf_tvar_{name}_{num}_tmp' variable to
       // our parent so it can be used as a substitute for the target
       // symbol.
-      provide <symbol*> (this, tmpsym);
+      provide (tmpsym);
 
       // (5) Remember this replacement since we might be able to reuse
       // it later if the same return probe references this target
@@ -4622,7 +4619,8 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
 
           // Ignore any variable that isn't accessible.
           tsym->saved_conversion_error = 0;
-          this->visit_target_symbol(tsym); // NB: throws nothing ...
+          expression *texp = tsym;
+          texp = require (texp); // NB: throws nothing ...
           if (tsym->saved_conversion_error) // ... but this is how we know it happened.
             {
 
@@ -4631,7 +4629,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
             {
               pf->raw_components += "return";
               pf->raw_components += "=%#x ";
-              pf->args.push_back(*(expression**)this->targets.top());
+              pf->args.push_back(texp);
             }
         }
       else
@@ -4665,7 +4663,8 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
 
                 // Ignore any variable that isn't accessible.
                 tsym->saved_conversion_error = 0;
-                this->visit_target_symbol(tsym); // NB: throws nothing ...
+                expression *texp = tsym;
+                texp = require (texp); // NB: throws nothing ...
                 if (tsym->saved_conversion_error) // ... but this is how we know it happened.
                   {
                     if (q.sess.verbose>2)
@@ -4684,14 +4683,14 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
                   {
                     pf->raw_components += diename;
                     pf->raw_components += "=%#x ";
-                    pf->args.push_back(*(expression**)this->targets.top());
+                    pf->args.push_back(texp);
                   }
               }
             while (dwarf_siblingof (&result, &result) == 0);
         }
 
       pf->components = print_format::string_to_components(pf->raw_components);
-      provide <print_format*> (this, pf);
+      provide (pf);
 
       return;
     }
@@ -4735,7 +4734,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
       // target_symbol to the next pass.  We hope that this value ends
       // up not being referenced after all, so it can be optimized out
       // quietly.
-      provide <target_symbol*> (this, e);
+      provide (e);
       semantic_error* saveme = new semantic_error (er); // copy it
       saveme->tok1 = e->tok; // XXX: token not passed to q.dw code generation routines
       // NB: we can have multiple errors, since a $target variable
@@ -4783,7 +4782,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
       *(target_symbol_setter_functioncalls.top()) = n;
     }
 
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 
@@ -4852,11 +4851,11 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
                           + lex_cast<string>(USHRT_MAX) + "]",
                           q.base_loc->tok);
 
-  // Make a target-variable-expanded copy of the probe body
+  // Expand target variables in the probe body
   if (!null_die(scope_die))
     {
-      dwarf_var_expanding_copy_visitor v (q, scope_die, dwfl_addr);
-      require <statement*> (&v, &(this->body), this->body);
+      dwarf_var_expanding_visitor v (q, scope_die, dwfl_addr);
+      this->body = v.require (this->body);
       this->access_vars = v.visited;
 
       // If during target-variable-expanding the probe, we added a new block
@@ -6240,10 +6239,10 @@ public:
 };
 
 
-struct utrace_var_expanding_copy_visitor: public var_expanding_copy_visitor
+struct utrace_var_expanding_visitor: public var_expanding_visitor
 {
-  utrace_var_expanding_copy_visitor(systemtap_session& s, const string& pn,
-                                   enum utrace_derived_probe_flags f):
+  utrace_var_expanding_visitor(systemtap_session& s, const string& pn,
+                               enum utrace_derived_probe_flags f):
     sess (s), probe_name (pn), flags (f), target_symbol_seen (false) {}
 
   systemtap_session& sess;
@@ -6266,9 +6265,9 @@ utrace_derived_probe::utrace_derived_probe (systemtap_session &s,
   has_path(hp), path(pn), pid(pd), flags(f),
   target_symbol_seen(false)
 {
-  // Make a local-variable-expanded copy of the probe body
-  utrace_var_expanding_copy_visitor v (s, name, flags);
-  require <statement*> (&v, &(this->body), base->body);
+  // Expand local variables in the probe body
+  utrace_var_expanding_visitor v (s, name, flags);
+  this->body = v.require (this->body);
   target_symbol_seen = v.target_symbol_seen;
 
   // Reset the sole element of the "locations" vector as a
@@ -6330,7 +6329,7 @@ utrace_derived_probe::join_group (systemtap_session& s)
 
 
 void
-utrace_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e)
+utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
 {
   string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
   int argnum = lex_cast<int>(argnum_s);
@@ -6379,11 +6378,11 @@ utrace_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e)
   num->tok = e->tok;
   n->args.push_back(num);
 
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 void
-utrace_var_expanding_copy_visitor::visit_target_symbol_context (target_symbol* e)
+utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
 {
   string sname = e->base_name;
 
@@ -6430,11 +6429,11 @@ utrace_var_expanding_copy_visitor::visit_target_symbol_context (target_symbol* e
   n->function = fname;
   n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
 
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 void
-utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
+utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
 {
   assert(e->base_name.size() > 0 && e->base_name[0] == '$');
 
@@ -6994,11 +6993,11 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function,
 
   this->tok = q.base_probe->tok;
 
-  // Make a target-variable-expanded copy of the probe body
+  // Expand target variables in the probe body
   if (!null_die(scope_die))
     {
-      dwarf_var_expanding_copy_visitor v (q, scope_die, dwfl_addr); // XXX: user-space deref's!
-      require <statement*> (&v, &(this->body), this->body);
+      dwarf_var_expanding_visitor v (q, scope_die, dwfl_addr); // XXX: user-space deref's!
+      this->body = v.require (this->body);
 
       // If during target-variable-expanding the probe, we added a new block
       // of code, add it to the start of the probe.
@@ -7779,10 +7778,10 @@ public:
 };
 
 
-struct procfs_var_expanding_copy_visitor: public var_expanding_copy_visitor
+struct procfs_var_expanding_visitor: public var_expanding_visitor
 {
-  procfs_var_expanding_copy_visitor(systemtap_session& s, const string& pn,
-                                   string path, bool write_probe):
+  procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
+                               string path, bool write_probe):
     sess (s), probe_name (pn), path (path), write_probe (write_probe),
     target_symbol_seen (false) {}
 
@@ -7800,9 +7799,9 @@ procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
                                            probe_point* l, string ps, bool w):
   derived_probe(p, l), path(ps), write(w), target_symbol_seen(false)
 {
-  // Make a local-variable-expanded copy of the probe body
-  procfs_var_expanding_copy_visitor v (s, name, path, write);
-  require <statement*> (&v, &(this->body), base->body);
+  // Expand local variables in the probe body
+  procfs_var_expanding_visitor v (s, name, path, write);
+  this->body = v.require (this->body);
   target_symbol_seen = v.target_symbol_seen;
 }
 
@@ -8051,7 +8050,7 @@ procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
 
 
 void
-procfs_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
+procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
 {
   assert(e->base_name.size() > 0 && e->base_name[0] == '$');
 
@@ -8136,7 +8135,7 @@ procfs_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
       *(target_symbol_setter_functioncalls.top()) = n;
     }
 
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 
@@ -8255,11 +8254,10 @@ public:
 };
 
 
-struct mark_var_expanding_copy_visitor: public var_expanding_copy_visitor
+struct mark_var_expanding_visitor: public var_expanding_visitor
 {
-  mark_var_expanding_copy_visitor(systemtap_session& s,
-                                  const string& pn,
-                                 vector <struct mark_arg *> &mark_args):
+  mark_var_expanding_visitor(systemtap_session& s, const string& pn,
+                             vector <struct mark_arg *> &mark_args):
     sess (s), probe_name (pn), mark_args (mark_args),
     target_symbol_seen (false) {}
   systemtap_session& sess;
@@ -8310,7 +8308,7 @@ hex_dump(unsigned char *data, size_t len)
 
 
 void
-mark_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e)
+mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
 {
   string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
   int argnum = atoi (argnum_s.c_str());
@@ -8371,12 +8369,12 @@ mark_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e)
   n->tok = e->tok;
   n->function = fname;
   n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 
 void
-mark_var_expanding_copy_visitor::visit_target_symbol_context (target_symbol* e)
+mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
 {
   string sname = e->base_name;
 
@@ -8413,11 +8411,11 @@ mark_var_expanding_copy_visitor::visit_target_symbol_context (target_symbol* e)
   n->tok = e->tok;
   n->function = fname;
   n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 void
-mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
+mark_var_expanding_visitor::visit_target_symbol (target_symbol* e)
 {
   assert(e->base_name.size() > 0 && e->base_name[0] == '$');
 
@@ -8450,9 +8448,9 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s,
   // expand the marker format
   parse_probe_format();
 
-  // Now make a local-variable-expanded copy of the probe body
-  mark_var_expanding_copy_visitor v (sess, name, mark_args);
-  require <statement*> (&v, &(this->body), base->body);
+  // Now expand the local variables in the probe body
+  mark_var_expanding_visitor v (sess, name, mark_args);
+  this->body = v.require (this->body);
   target_symbol_seen = v.target_symbol_seen;
 
   if (sess.verbose > 2)
@@ -9220,18 +9218,18 @@ timer_builder::register_patterns(match_node *root)
 //
 
 
-struct perfmon_var_expanding_copy_visitor: public var_expanding_copy_visitor
+struct perfmon_var_expanding_visitor: public var_expanding_visitor
 {
   systemtap_session & sess;
   unsigned counter_number;
-  perfmon_var_expanding_copy_visitor(systemtap_session & s, unsigned c):
+  perfmon_var_expanding_visitor(systemtap_session & s, unsigned c):
          sess(s), counter_number(c) {}
   void visit_target_symbol (target_symbol* e);
 };
 
 
 void
-perfmon_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
+perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e)
 {
   assert(e->base_name.size() > 0 && e->base_name[0] == '$');
 
@@ -9285,7 +9283,7 @@ perfmon_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
   n->function = fname;
   n->referent = 0;  // NB: must not resolve yet, to ensure inclusion in session
 
-  provide <functioncall*> (this, n);
+  provide (n);
 }
 
 
@@ -9353,9 +9351,9 @@ perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
 {
   ++probes_allocated;
 
-  // Now make a local-variable-expanded copy of the probe body
-  perfmon_var_expanding_copy_visitor v (sess, probes_allocated-1);
-  require <statement*> (&v, &(this->body), base->body);
+  // Now expand the local variables in the probe body
+  perfmon_var_expanding_visitor v (sess, probes_allocated-1);
+  this->body = v.require (this->body);
 
   if (sess.verbose > 1)
     clog << "perfmon-based probe" << endl;
This page took 0.097196 seconds and 5 git commands to generate.