From: Justin Seyster Date: Thu, 1 Apr 2010 20:27:35 +0000 (-0400) Subject: Added support for aop_capture_lhs_addr() on assignment pointcuts. X-Git-Tag: release-v1.0~111 X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=61e7dfaedab65a5d7abaad4e6893b08a3e2944b2;p=interaspect.git Added support for aop_capture_lhs_addr() on assignment pointcuts. --- diff --git a/src/aop-pc-assign.c b/src/aop-pc-assign.c index 0e54209..37e5b96 100644 --- a/src/aop-pc-assign.c +++ b/src/aop-pc-assign.c @@ -30,12 +30,22 @@ #include #include #include +#include #include #include "aop.h" +#include "aop-dynval.h" #include "aop-pointcut.h" #include "aop-type.h" +/** + * Get the name of the variable being assigned to in an assignment + * joinpoint. + * \param jp An assignment joinpoint. Assignment joinpoints are + * obtained by joining on an aop_match_assignment_by_type() pointcut. + * \return For a direct assignment to a variable, the name of that + * variable, otherwise NULL. + */ const char * aop_capture_lhs_name (struct aop_joinpoint *jp) { @@ -65,13 +75,119 @@ aop_capture_lhs_name (struct aop_joinpoint *jp) } } +/* Given an expression from the lhs of an assignment, return true + unless it is a temporary variable created by the compiler. + + Generally, users will not be interested in instrumenting those temp + variables that return false here. */ +static bool +lhs_is_real (tree lhs) +{ + if (TREE_CODE (lhs) == SSA_NAME) + lhs = SSA_NAME_VAR (lhs); + + /* DECL_VAR nodes with DECL_ARTIFICIAL set represent temporary + variables. */ + if (TREE_CODE (lhs) == VAR_DECL) + return !DECL_ARTIFICIAL (lhs); + else + return true; +} + +/* This gets called when weaving an advice function that evaluates an + aop_capture_lhs_addr() dynval. It does the actual work of + inserting statements to get a reference to &lhs and then returns + that reference. */ +static tree +op_get_lhs_addr (struct aop_dynval *dv) +{ + gimple stmt; + tree lhs; + tree lhs_pointer; + + struct aop_joinpoint *jp = dv->jp; + + aop_assert (dv->kind == ADV_LHS_ADDR); + aop_assert (jp->pc->kind == ATP_ASSIGN); + + stmt = jp->stmt; + aop_assert (gimple_has_lhs (stmt)); + lhs = gimple_get_lhs (stmt); + + aop_assert (lhs_is_real (lhs)); + + if (TREE_CODE (lhs) == SSA_NAME) + lhs = SSA_NAME_VAR (lhs); + + /* GCC only marks a variable as addressable if the program actually + takes its address (allowing certain optimizations on those + variables that are not addressable). In order to take the + address ourselves, we must make sure that the variable is marked + addressable. */ + mark_addressable (lhs); + lhs_pointer = build1 (ADDR_EXPR, build_pointer_type (void_type_node), + stabilize_reference (lhs)); + + /* If mark_addressable() fails to make a variable addressable, it is + impossible to address that variable. */ + aop_assert (is_gimple_address (lhs_pointer)); + + return lhs_pointer; +} + +/** + * Get a dynval representing the address of the variable being + * assigned to at an assignment joinpoint. + * Note that this capture function will return NULL if the joinpoint + * is an assignment to a temporary variable: temporary variables are + * never addressable. You only need to worry about non-addressable + * temporary variables in a pointcut if you filter it with + * aop_filter_include_temps(). + * \param jp An assignment joinpoint. Assignment joinpoints are + * obtained by joining on an aop_match_assignment_by_type() pointcut. + * \return A dynval with (void *) type or NULL if the assignment + * target is not addressable. + */ +struct aop_dynval * +aop_capture_lhs_addr (struct aop_joinpoint *jp) +{ + tree lhs; + struct aop_dynval *dv; + + aop_assert (jp->pc->kind == ATP_ASSIGN); + + /* Is this a temporary? */ + aop_assert (gimple_has_lhs (jp->stmt)); + lhs = gimple_get_lhs (jp->stmt); + if (!lhs_is_real (lhs)) + { + /* We should only see temp vars if this is a pointcut that + includes them. */ + aop_assert (jp->pc->pc_assign.include_temp_vars); + return NULL; + } + + dv = ggc_alloc (sizeof (struct aop_dynval)); + dv->kind = ADV_LHS_ADDR; + dv->type = aop_t_all_pointer (); + dv->jp = jp; + dv->get_dynval = op_get_lhs_addr; + + return dv; +} + static bool stmt_matches_pointcut (struct aop_pointcut *pc, gimple stmt) { if (gimple_has_lhs (stmt)) { + tree lhs = gimple_get_lhs(stmt); tree type = TREE_TYPE (gimple_get_lhs (stmt)); - return does_type_match (type, pc->pc_assign.type); + + /* Temp variables with matching type only match the pointcut if + include_temp_vars is true. */ + return does_type_match (type, pc->pc_assign.type) + && (pc->pc_assign.include_temp_vars || lhs_is_real (lhs)); } else { @@ -100,6 +216,7 @@ op_join_on_assign (struct aop_pointcut *pc, join_callback cb, struct aop_joinpoint jp; jp.pc = pc; jp.gsi = &gsi; + jp.stmt = stmt; cb (&jp, callback_param); } @@ -107,17 +224,55 @@ op_join_on_assign (struct aop_pointcut *pc, join_callback cb, } } +/** + * Include compiler-created temporary variables in an assignment + * pointcut. + * + * By default, assignment pointcuts do not include assignments to + * temporary variables. These assignments will usually only be useful + * to users trying to debug the compiler with InterAsepct. + * \param pc The pointcut to modify with the filter. + */ +void +aop_filter_include_temps (struct aop_pointcut *pc) +{ + aop_assert (pc->kind == ATP_ASSIGN); + pc->pc_assign.include_temp_vars = true; +} + +/** + * Exclude compiler-created temporary variables from an assignment + * pointcut. + * + * This function is provided to undo the effect of + * aop_filter_include_temps(); by default, you do not need to call it. + * \param pc The pointcut to modify with the filter. + */ +void +aop_filter_exclude_temps (struct aop_pointcut *pc) +{ + aop_assert (pc->kind == ATP_ASSIGN); + pc->pc_assign.include_temp_vars = false; +} + +/** + * Return a pointcut that matches all assignments to a variable with + * the given type. + * \param type The type to filter assignments by. + * \return The resulting pointcut. + */ struct aop_pointcut * aop_match_assignment_by_type (const struct aop_type *type) { struct aop_pointcut *pc; - pc = ggc_alloc (sizeof (struct aop_pointcut *)); + pc = ggc_alloc (sizeof (struct aop_pointcut)); pc->kind = ATP_ASSIGN; pc->join_on = op_join_on_assign; pc->insert_before = op_default_insert_before; pc->pc_assign.type = type; + pc->pc_assign.include_temp_vars = false; return pc; } diff --git a/src/aop-pointcut.h b/src/aop-pointcut.h index cfba5fc..85420b3 100644 --- a/src/aop-pointcut.h +++ b/src/aop-pointcut.h @@ -18,6 +18,8 @@ /* This is a private header. Do not include it in source file for client plug-ins. */ +#include "aop-callback.h" + struct aop_type; enum aop_pckind { @@ -26,11 +28,16 @@ enum aop_pckind { ATP_EXIT, }; +/* Information specific to assignment pointcuts. */ struct aop_pc_assign { const struct aop_type *type; + + /* If true, include assignments to temporary variables in the + pointcut. This is false by default. */ + bool include_temp_vars; }; -/* An AOP pointcut represents the a set of joinponts: locations in the +/* An AOP pointcut represents a set of joinponts: locations in the source code that are available for inserting instrumentation. In practice, we do not directly store the set of joinpoints. @@ -40,7 +47,7 @@ struct aop_pointcut { enum aop_pckind kind; void (*join_on) (struct aop_pointcut *, join_callback, void *); - void (*insert_before) (struct aop_joinpoint *, gimple); + insert_callback insert_before; union { struct aop_pc_assign pc_assign; @@ -58,6 +65,9 @@ struct aop_joinpoint { /* A GCC iterator for where weave functions can insert their instrumentation.*/ gimple_stmt_iterator *gsi; + + /* The GIMPLE statement being instrumented (where relevant). */ + gimple stmt; }; void op_default_insert_before (struct aop_joinpoint *jp, gimple stmt); diff --git a/src/aop.h b/src/aop.h index 6f53d8a..3675615 100644 --- a/src/aop.h +++ b/src/aop.h @@ -47,6 +47,7 @@ #define aop_assert(EXPR) ((void)(0 && (EXPR))) #endif +struct aop_dynval; struct aop_joinpoint; struct aop_pointcut; struct aop_type; @@ -57,6 +58,9 @@ typedef void (*join_callback) (struct aop_joinpoint *, void *callback_param); extern struct aop_pointcut *aop_match_assignment_by_type ( const struct aop_type *type); +extern void aop_filter_include_temps (struct aop_pointcut *pc); +extern void aop_filter_exclude_temps (struct aop_pointcut *pc); + extern const char *aop_capture_lhs_name (struct aop_joinpoint *jp); extern void aop_insert_advice (struct aop_joinpoint *jp, const char *name, ...); @@ -87,6 +91,7 @@ enum aop_argkind { #define AOP_DYNVAL(VAL) ATA_DYNVAL, VAL const char *aop_capture_function_name (struct aop_joinpoint *jp); +struct aop_dynval *aop_capture_lhs_addr (struct aop_joinpoint *jp); struct aop_pointcut *aop_match_function_entry (); struct aop_pointcut *aop_match_function_exit ();