#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"
}
}
+/* 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)
{
{
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;
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. */
/**
* \}