Cleaned up function exit pointcuts so that after advice works.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Fri, 18 Jun 2010 21:12:44 +0000 (17:12 -0400)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Fri, 18 Jun 2010 21:12:44 +0000 (17:12 -0400)
Also documented the use of before and after advice in detail in the
aop_insert_advice() documentation.

src/aop-pc-exit.c
src/aop-weave.c

index 3dbe43b717c3efc0f45048d3853087c17c9fcaf7..c8b7fc76c156ef8096e406ae768a90be8eb6694b 100644 (file)
@@ -48,22 +48,52 @@ op_join_on_function_exit (struct aop_pointcut *pc, join_callback cb,
   FOR_EACH_BB(bb)
     {
       gimple_stmt_iterator gsi;
-      for (gsi = gsi_start_bb(bb) ; !gsi_end_p(gsi) ; gsi_next(&gsi)) 
+      for (gsi = gsi_start_bb (bb) ; !gsi_end_p (gsi) ; gsi_next (&gsi)) 
        {
          stmt = gsi_stmt (gsi);
-         
+
          if (gimple_code (stmt) == GIMPLE_RETURN)
            {
              struct aop_joinpoint jp;
              jp.pc = pc;
              jp.gsi = &gsi;
+             jp.stmt = stmt;
              jp.is_prepared = false;
              cb (&jp, callback_param);
+
+             /* It's possible that gsi is no longer a valid iterator
+                if the callback inserted advice.  Anyway, that's fine
+                because there shouldn't be any statements in the
+                basic block after the return!  On to the next basic
+                block. */
+             break;
            }
        }
     } 
 }
 
+/* Prepare for an insert at a function entry join point.
+
+   Attempting to insert an advice call _after_ a return statement
+   doesn't make any sense and will fail.  GIMPLE does not allow any
+   statements in a basic block after a return statement (sensibly).
+
+   We create a NOP statement before the return statement that serves
+   as an anchor for inserting advice.  Any advice calls inserted with
+   AOP_INSERT_AFTER will still execute before the return but will
+   execute after any calls inserted with AOP_INSERT_BEFORE (no matter
+   the order in which they were inserted). */
+static void
+op_prepare_exit (struct aop_joinpoint *jp)
+{
+  gimple nop;
+
+  aop_assert (jp->pc->kind == ATP_EXIT);
+
+  nop = gimple_build_nop ();
+  gsi_insert_before (jp->gsi, nop, GSI_NEW_STMT);
+}
+
 struct aop_pointcut *
 aop_match_function_exit ()
 {
@@ -72,6 +102,7 @@ aop_match_function_exit ()
   pc->kind = ATP_EXIT;
   pc->join_on = op_join_on_function_exit;
   pc->insert_before = op_default_insert_before;
-  pc->prepare_for_weave = op_default_prepare_for_weave;
+  pc->insert_after = op_default_insert_after;
+  pc->prepare_for_weave = op_prepare_exit;
   return pc;
 }
index 769b83ebb44b0be4b8dbc5286a5f740cca6cd8b5..4016a06683720ff8d90ebb4f084088fe7cbf872b 100644 (file)
@@ -166,6 +166,33 @@ op_default_prepare_for_weave (struct aop_joinpoint *jp)
   /* This space intentionally left blank. */
 }
 
+/**
+ * Insert a call to an advice function at a join point with any number
+ * of arguments.  Any arguments following location are arguments to be
+ * passed to the advice function.  Because C does not know the types
+ * of vararg arguments, a type macro (such as #AOP_STR_CST or
+ * #AOP_DYNVAL) is necessary for each advice argument.  #AOP_TERM_ARG
+ * must be the last argument to aop_insert_advice(), even when not
+ * specifying any arguments for the advice function.
+ *
+ * Specifying AOP_INSERT_BEFORE or AOP_INSERT_AFTER will place the
+ * call before or after the join point (when possible) and will
+ * guarantee certain properties about ordering of advice calls.  Using
+ * AOP_INSERT_BEFORE to insert multiple advice calls at the same join
+ * point will place advice calls in the order they are inserted.  With
+ * AOP_INSERT_AFTER, however, advice calls will be placed in _reverse_
+ * order.  No matter what order calls are inserted in, all
+ * AOP_INSERT_BEFORE calls will be placed before all AOP_INSERT_AFTER
+ * calls.
+ *
+ * It is legal to use AOP_INSERT_BEFORE and AOP_INSERT_AFTER to
+ * enforce ordering among advice calls even when inserting before or
+ * after a join point does not make sense.  For example, it does not
+ * make sense to insert an advice call before a function entry join
+ * point.  Using AOP_INSERT_BEFORE will still insert the advice after
+ * function entry, but it will place the advice before any
+ * AOP_INSERT_AFTER advice.
+ */
 void
 aop_insert_advice (struct aop_joinpoint *jp, const char *func_name, 
                   enum aop_insert_location location, ...)