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)
{
jp.pc = pc;
jp.gsi = &gsi;
jp.stmt = stmt;
+ jp.is_prepared = false;
cb (&jp, callback_param);
}
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;
#include "aop-callback.h"
+struct aop_joinpoint;
struct aop_type;
enum aop_pckind {
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;
};
/* 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
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, ...)
{
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);
}