Added filtering and capturing on return value for exit join points.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Thu, 21 Oct 2010 02:53:58 +0000 (22:53 -0400)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Thu, 21 Oct 2010 02:53:58 +0000 (22:53 -0400)
src/aop-dynval.h
src/aop-pc-exit.c
src/aop-pointcut.h
src/aop.h

index 1a3008ee7c822879f8d80bdbe5f399275acacec2..0504ae7835d3a53be8d22cf5b7fcd9dde7f1bb35 100644 (file)
@@ -34,6 +34,7 @@ enum aop_dvkind {
   ADV_LHS_ADDR,
   ADV_FUN_PARAM,
   ADV_FUN_RETVAL,
+  ADV_EXIT_RETVAL,
   ADV_ASSIGN_VAL,
 };
 
index 434d62f1118d4c399629f411d5cce398c7443aec..cc78f028c12f70912f867be84e7b5f3c46d36dea 100644 (file)
 #include <tree.h>
 #include <ggc.h>
 #include <basic-block.h>
+#include <toplev.h>
 #include <diagnostic.h>
 #include <gimple.h>
 
 #include "aop.h"
 #include "aop-duplicate.h"
+#include "aop-dynval.h"
 #include "aop-pointcut.h"
 #include "aop-type.h"
 
@@ -80,13 +82,35 @@ join_on_bb_function_exit (basic_block bb, struct aop_pointcut *pc,
     }
 }
 
+/* Return true if the current function's return type matches the
+   specified type. */
+static bool
+return_type_matches (const struct aop_type *type)
+{
+  tree cfun_type;
+  tree cfun_return_type;
+
+  cfun_type = TREE_TYPE (current_function_decl);
+
+  aop_assert (cfun_type != NULL && TREE_CODE (cfun_type) == FUNCTION_TYPE);
+  cfun_return_type = TREE_TYPE (cfun_type);
+
+  return does_type_match (cfun_return_type, type);
+}
+
 static void
 op_join_on_function_exit (struct aop_pointcut *pc, join_callback cb, 
                          void *callback_param)
 {
   basic_block bb;
+  const struct aop_type *return_type_filter;
 
   aop_assert (pc->kind == ATP_EXIT);
+
+  /* Filter by return type? */
+  return_type_filter = pc->pc_exit.return_type;
+  if (return_type_filter != NULL && !return_type_matches(return_type_filter))
+    return;  /* Treat as an empty pointcut. */
   
   FOR_EACH_BB(bb)
     {
@@ -100,10 +124,16 @@ op_join_on_copy_function_exit (struct aop_pointcut *pc, int copy,
 {
   unsigned int pair_index;
   bb_pair *pair;
+  const struct aop_type *return_type_filter;
 
   aop_assert (pc->kind == ATP_EXIT);
   aop_assert (is_current_func_duplicated ());
   
+  /* Filter by return type? */
+  return_type_filter = pc->pc_exit.return_type;
+  if (return_type_filter != NULL && !return_type_matches(return_type_filter))
+    return;  /* Treat as an empty pointcut. */
+  
   FOR_EACH_BB_PAIR (bb_pairs, pair_index, pair)
     {
       basic_block bb = (copy == 0) ? pair->old : pair->new;
@@ -150,9 +180,87 @@ aop_match_function_exit ()
   pc->join_on_copy = op_join_on_copy_function_exit;
   pc->prepare_for_weave = op_prepare_exit;
 
+  pc->pc_exit.return_type = NULL;
+
   return pc;
 }
 
+/**
+ * Filter a function exit pointcut by the function's return type.
+ * This is an all-or-nothing filter: because all the function's return
+ * statements will have the same type, either all of the exit join
+ * points will be filtered out or none will.
+ * 
+ * Note that you must filter a pointcut by return type in order to
+ * call aop_capture_exit_return_value() on any of its join points.
+ *
+ * \param pc The function exit pointcut to filter.  Function exit
+ * pointcuts are created with aop_match_function_exit().
+ * \param type The return type to filter by.
+ */
+void
+aop_filter_exit_by_return_type (struct aop_pointcut *pc,
+                               const struct aop_type *type)
+{
+  if (pc->kind != ATP_EXIT)
+    fatal_error ("(InterAspect) Attempt to filter by return type on"
+                " unsupported join point.");
+
+  pc->pc_exit.return_type = type;
+}
+
+static tree
+op_get_exit_return_value (struct aop_dynval *dv)
+{
+  gimple stmt;
+  tree return_value;
+
+  struct aop_joinpoint *jp = dv->jp;
+  stmt = jp->stmt;
+
+  aop_assert (gimple_code (stmt) == GIMPLE_RETURN);
+
+  if (gimple_return_retval (stmt) == NULL)
+    fatal_error ("(InterAspect) Attempt to capture return value from function"
+                " that does not always return a value.");
+
+  return_value = stabilize_reference (gimple_return_retval (stmt));
+  return return_value;
+}
+
+/**
+ * Get a dynval representing the value returned at a function exit
+ * join point.  Note that you must filter with
+ * aop_filter_exit_by_return_type() in order to capture the return
+ * value using aop_capture_exit_return_value().
+ * \param jp A function exit join point.  Function exit join points
+ * are obtained by joining on an aop_match_function_exit() pointcut.
+ * \param A dynval with its type determined by
+ * aop_filter_exit_by_return_type().
+ */
+struct aop_dynval *
+aop_capture_exit_return_value (struct aop_joinpoint *jp)
+{
+  struct aop_pointcut *pc;
+  struct aop_dynval *dv;
+
+  pc = jp->pc;
+  if (pc->kind != ATP_EXIT)
+    fatal_error ("(InterAspect) Attempt to capture return value from an"
+                " unsupported join point.");
+
+  if (pc->pc_exit.return_type == NULL)
+    fatal_error ("(InterAspect) Attempt to capture return value without"
+                " specifying type.");
+
+  dv = ggc_alloc (sizeof (struct aop_dynval));
+  dv->kind = ADV_EXIT_RETVAL;
+  dv->type = pc->pc_exit.return_type;
+  dv->jp = jp;
+  dv->get_dynval = op_get_exit_return_value;
+  return dv;
+}
+
 /* Close Doxygen defgroup block. */
 /**
  * \}
index 6f66b80b9f65ef12e096f2cd92fae1be753d68b3..1449d5f45dfb71c95cb29e8ad2fba9aa136d3788 100644 (file)
@@ -62,6 +62,10 @@ struct aop_pc_entry {
   const char *function_name;
 };
 
+struct aop_pc_exit {
+  const struct aop_type *return_type;
+};
+
 struct aop_pc_fun_call {
   const char *function_name;
   const struct aop_type *return_type;
@@ -91,6 +95,7 @@ struct aop_pointcut {
   union {
     struct aop_pc_assign pc_assign;
     struct aop_pc_entry pc_entry;
+    struct aop_pc_exit pc_exit;
     struct aop_pc_fun_call pc_call;
   };
 
index 8e20f7bac4dcf0eb8dd225c679cea494c5281e53..411e3c33654b206e52dd26d4f336774277fa078a 100644 (file)
--- a/src/aop.h
+++ b/src/aop.h
@@ -332,11 +332,15 @@ extern void aop_filter_by_in_param (struct aop_pointcut *pc, int n,
 extern struct aop_dynval *aop_capture_in_param (struct aop_joinpoint *jp,
                                             int param_index);
 
-extern struct aop_pointcut *aop_match_function_exit ();
-
 extern void aop_filter_entry_by_name(struct aop_pointcut *pc_function_entry,
                                     const char *advice_function_entry);
 
+extern struct aop_pointcut *aop_match_function_exit ();
+extern void aop_filter_exit_by_return_type (struct aop_pointcut *pc,
+                                           const struct aop_type *type);
+struct aop_dynval *aop_capture_exit_return_value (struct aop_joinpoint *jp);
+
+
 extern struct aop_pointcut *aop_match_function_call ();
 
 extern void aop_filter_call_pc_by_name (struct aop_pointcut *pc_function_call,