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 ()
{
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;
}
/* 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, ...)