From: Justin Seyster Date: Thu, 20 May 2010 00:28:13 +0000 (-0400) Subject: Added ability to capture the value of an assignment. X-Git-Tag: release-v1.0~105^2 X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=10c43393020c161108fc5abbec57c8f513914142;p=interaspect.git Added ability to capture the value of an assignment. With this patch, instrumented assignments get broken up into two parts, one that assigns to a temp variable and one that assigns the temp variable to the actual assignment target variable. This split makes several things simpler, including capturing the value of the rhs. In order to perform this split, the patch also introduces a prepare function, which will only get called once for a given join point: right before the first time it is instrumented with advice. --- diff --git a/src/aop-dynval.h b/src/aop-dynval.h index 0af81f1..b63bc0e 100644 --- a/src/aop-dynval.h +++ b/src/aop-dynval.h @@ -23,6 +23,7 @@ struct aop_type; enum aop_dvkind { ADV_LHS_ADDR, + ADV_ASSIGN_VAL, }; /* An aop-dynval represents a dynamic value in the target program that diff --git a/src/aop-pc-assign.c b/src/aop-pc-assign.c index 37e5b96..6600437 100644 --- a/src/aop-pc-assign.c +++ b/src/aop-pc-assign.c @@ -176,6 +176,88 @@ aop_capture_lhs_addr (struct aop_joinpoint *jp) 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) { @@ -217,6 +299,7 @@ op_join_on_assign (struct aop_pointcut *pc, join_callback cb, jp.pc = pc; jp.gsi = &gsi; jp.stmt = stmt; + jp.is_prepared = false; cb (&jp, callback_param); } @@ -270,6 +353,7 @@ aop_match_assignment_by_type (const struct aop_type *type) 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; diff --git a/src/aop-pointcut.h b/src/aop-pointcut.h index 85420b3..d462ec4 100644 --- a/src/aop-pointcut.h +++ b/src/aop-pointcut.h @@ -20,6 +20,7 @@ #include "aop-callback.h" +struct aop_joinpoint; struct aop_type; enum aop_pckind { @@ -49,6 +50,10 @@ struct aop_pointcut { 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; }; @@ -68,8 +73,13 @@ struct aop_joinpoint { /* 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 diff --git a/src/aop-weave.c b/src/aop-weave.c index 831502d..2d02e4c 100644 --- a/src/aop-weave.c +++ b/src/aop-weave.c @@ -145,6 +145,14 @@ op_default_insert_before (struct aop_joinpoint *jp, gimple stmt) 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, ...) { @@ -152,10 +160,18 @@ 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); } diff --git a/src/aop.h b/src/aop.h index 3675615..cae23b3 100644 --- a/src/aop.h +++ b/src/aop.h @@ -92,6 +92,7 @@ enum aop_argkind { const char *aop_capture_function_name (struct aop_joinpoint *jp); struct aop_dynval *aop_capture_lhs_addr (struct aop_joinpoint *jp); +struct aop_dynval *aop_capture_assigned_value (struct aop_joinpoint *jp); struct aop_pointcut *aop_match_function_entry (); struct aop_pointcut *aop_match_function_exit ();