Added ability to capture the value of an assignment.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Thu, 20 May 2010 00:28:13 +0000 (20:28 -0400)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Thu, 20 May 2010 00:28:13 +0000 (20:28 -0400)
With this patch, instrumented assignments get broken up into two
parts, one that assigns to a temp variable and one that assigns the
temp variable to the actual assignment target variable.  This split
makes several things simpler, including capturing the value of the
rhs.

In order to perform this split, the patch also introduces a prepare
function, which will only get called once for a given join point:
right before the first time it is instrumented with advice.

src/aop-dynval.h
src/aop-pc-assign.c
src/aop-pointcut.h
src/aop-weave.c
src/aop.h

index 0af81f1960d5a8b8925420392b4421b5157428ef..b63bc0e3a4cb145a7ead32c19d8935d33f878582 100644 (file)
@@ -23,6 +23,7 @@ struct aop_type;
 
 enum aop_dvkind {
   ADV_LHS_ADDR,
+  ADV_ASSIGN_VAL,
 };
 
 /* An aop-dynval represents a dynamic value in the target program that
index 37e5b9637193e12de129304b1912bcf2873b1f7d..66004377745a9ea051098953bf4a049ac6343b57 100644 (file)
@@ -176,6 +176,88 @@ aop_capture_lhs_addr (struct aop_joinpoint *jp)
   return dv;
 }
 
+/* This gets called when weaving a dynval created with
+   aop_capture_assigned_value().  It returns a tree that will evaluate
+   to the assigned value. */
+static tree
+op_get_assigned_value (struct aop_dynval *dv)
+{
+  gimple stmt;
+
+  struct aop_joinpoint *jp = dv->jp;
+
+  aop_assert (dv->kind == ADV_ASSIGN_VAL);
+  aop_assert (jp->pc->kind == ATP_ASSIGN);
+
+  stmt = jp->stmt;
+  aop_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
+
+  /* op_prepare_assign rekajiggers the assignment so we are guaranteed
+     it is a simple a = b style of assignment.  That is, we don't have
+     to worry if there is an operation or a function call on the right
+     hand side.  The assigned value is a simple variable that we can
+     return directly. */
+  return gimple_op (stmt, 1);
+}
+
+/***
+ * Get a dynval for the value being assigned at an assignment
+ * joinpoint.
+ * \param jp An assignment joinpoint.  Assignment joinpoints are
+ * obtained by joining on an aop_match_assignment_by_type() pointcut.
+ * \return A dynval with type corresponding the the assignment
+ * pointcut's type.
+ */
+struct aop_dynval *
+aop_capture_assigned_value (struct aop_joinpoint *jp)
+{
+  struct aop_dynval *dv;
+
+  aop_assert (jp->pc->kind == ATP_ASSIGN);
+
+  dv = ggc_alloc (sizeof (struct aop_dynval));
+  dv->kind = ADV_ASSIGN_VAL;
+  dv->type = jp->pc->pc_assign.type;
+  dv->jp = jp;
+  dv->get_dynval = op_get_assigned_value;
+
+  return dv;
+}
+
+static void
+op_prepare_assign (struct aop_joinpoint *jp)
+{
+  tree real_lhs;
+  tree tmp_lhs;
+  gimple new_assign;
+
+  aop_assert (jp->pc->kind == ATP_ASSIGN);
+
+  /* We have a statement that something looks like:
+     real_lhs = foo(...);
+
+     We want to transform it to:
+     tmp_lhs = foo(...);
+     real_lhs = tmp_lhs;
+
+     That way, any advice inserted before the assignment will still
+     get called after the function call. 
+
+     Even when the assignment does not have a function call, splitting
+     the assignment like this makes it much easier to capture the
+     assigned value.  */
+  real_lhs = gimple_get_lhs (jp->stmt);
+  tmp_lhs = create_tmp_var (TREE_TYPE (real_lhs), "ia_tmp_lhs");
+
+  /* Substitute tmp_lhs for real_lhs. */
+  gimple_set_lhs (jp->stmt, tmp_lhs);
+
+  /* Insert the new assignment. */
+  new_assign = gimple_build_assign (real_lhs, tmp_lhs);
+  gsi_insert_after (jp->gsi, new_assign, GSI_NEW_STMT);
+  jp->stmt = new_assign;
+}
+
 static bool
 stmt_matches_pointcut (struct aop_pointcut *pc, gimple stmt)
 {
@@ -217,6 +299,7 @@ op_join_on_assign (struct aop_pointcut *pc, join_callback cb,
              jp.pc = pc;
              jp.gsi = &gsi;
              jp.stmt = stmt;
+             jp.is_prepared = false;
 
              cb (&jp, callback_param);
            }
@@ -270,6 +353,7 @@ aop_match_assignment_by_type (const struct aop_type *type)
   pc->kind = ATP_ASSIGN;
   pc->join_on = op_join_on_assign;
   pc->insert_before = op_default_insert_before;
+  pc->prepare_for_weave = op_prepare_assign;
 
   pc->pc_assign.type = type;
   pc->pc_assign.include_temp_vars = false;
index 85420b331e8e633e9c67f6716cfdba320b20007c..d462ec44af10c27e9ff8304cec506f398ae1daef 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "aop-callback.h"
 
+struct aop_joinpoint;
 struct aop_type;
 
 enum aop_pckind {
@@ -49,6 +50,10 @@ struct aop_pointcut {
   void (*join_on) (struct aop_pointcut *, join_callback, void *);
   insert_callback insert_before;
 
+  /* prepare_for_weave() gets called once for each joinpoint before
+     any advice gets inserted at that joinpoint.  */
+  void (*prepare_for_weave) (struct aop_joinpoint *);
+
   union {
     struct aop_pc_assign pc_assign;
   };
@@ -68,8 +73,13 @@ struct aop_joinpoint {
 
   /* The GIMPLE statement being instrumented (where relevant). */
   gimple stmt;
+
+  /* True if prepare_for_weave() has been called for this
+     joinpoint. */
+  bool is_prepared;
 };
 
+void op_default_prepare_for_weave (struct aop_joinpoint *jp);
 void op_default_insert_before (struct aop_joinpoint *jp, gimple stmt);
 
 #endif
index 831502dd8fd05252f08e80a3d2db2385bd1547c3..2d02e4cb786e6f4fffa3385d4d893cf516de8bb6 100644 (file)
@@ -145,6 +145,14 @@ op_default_insert_before (struct aop_joinpoint *jp, gimple stmt)
   gsi_insert_before (jp->gsi, stmt, GSI_SAME_STMT);
 }
 
+/* This is the default prepare_for_weave() operation for aop_pointcut
+   objects.  It does nothing. */
+void
+op_default_prepare_for_weave (struct aop_joinpoint *jp)
+{
+  /* This space intentionally left blank. */
+}
+
 void
 aop_insert_advice (struct aop_joinpoint *jp, const char *func_name, ...)
 {
@@ -152,10 +160,18 @@ aop_insert_advice (struct aop_joinpoint *jp, const char *func_name, ...)
   gimple func_call;
   struct aop_pointcut *pc;
 
+  pc = jp->pc;
+
+  /* Make sure this joinpoint is prepared for advice. */
+  if (!jp->is_prepared)
+    {
+      pc->prepare_for_weave (jp);
+      jp->is_prepared = true;
+    }
+
   va_start (argp, func_name);
   func_call = build_gcc_call (func_name, void_type_node, argp);
   va_end (argp);
 
-  pc = jp->pc;
   pc->insert_before(jp, func_call);
 }
index 36756156fe8ef5e358ce7e530078574b4f0fd721..cae23b3c3b973921185d2bbe53c086a66824155f 100644 (file)
--- a/src/aop.h
+++ b/src/aop.h
@@ -92,6 +92,7 @@ enum aop_argkind {
 
 const char *aop_capture_function_name (struct aop_joinpoint *jp);
 struct aop_dynval *aop_capture_lhs_addr (struct aop_joinpoint *jp);
+struct aop_dynval *aop_capture_assigned_value (struct aop_joinpoint *jp);
 struct aop_pointcut *aop_match_function_entry ();
 struct aop_pointcut *aop_match_function_exit ();