register_attribute_once(&noinstr_attr);
}
+static void
+remember_function_decl_pass(void *event_data, void *data)
+{
+ tree fndecl = (tree)event_data;
+ remember_function_decl(fndecl);
+}
+
/* This pass gets called before any passes that the client plug-in
registers. It's here for any administrative details that need to
take place before the instrumentation passes can execute. */
plugin_argc = plugin_info->argc;
plugin_argv = plugin_info->argv;
- /* Initialization for aop-type.c and aop-header.c. */
+ /* Initialization for aop-type.c, aop-header.c, and aop-weave.c. */
init_type_table ();
init_prototype_table ();
+ init_static_inline_table ();
/* Register attributes. */
register_callback(aop_plugin_name, PLUGIN_ATTRIBUTES, register_plugin_attributes, NULL);
+ /* Register ctree pass. */
+ register_callback(aop_plugin_name, PLUGIN_PRE_GENERICIZE, remember_function_decl_pass, NULL);
+
/* Register our cleanup function. */
register_callback (aop_plugin_name, PLUGIN_FINISH, aop_cleanup, NULL);
#include <coretypes.h>
#include <tm.h>
#include <tree.h>
+#include <c-common.h>
#include <gimple.h>
#include <tree-flow.h>
return (slot != NULL);
}
+/* This table holds the decl for every static inline we enocunter. We
+ want to remember these decls in case they get inserted as advice,
+ in which case we need the original decl so that GCC can perform the
+ inlining.
+
+ NB: At allocation, we store this on the heap (i.e., not in garbage
+ collected memory) because it doesn't get freed then reallocated
+ between passes. */
+static htab_t static_inline_decls = NULL;
+
+static hashval_t
+hash_decl_by_name (const void *entry)
+{
+ tree decl = (tree)entry;
+ const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+
+ return htab_hash_string (name);
+}
+
+static int
+hash_decl_name_eq (const void *entry1, const void *entry2)
+{
+ tree decl1 = (tree)entry1;
+ tree decl2 = (tree)entry2;
+
+ const char *name1 = IDENTIFIER_POINTER (DECL_NAME (decl1));
+ const char *name2 = IDENTIFIER_POINTER (DECL_NAME (decl2));
+
+ return (strcmp (name1, name2) == 0);
+}
+
+void
+init_static_inline_table ()
+{
+ static_inline_decls = htab_create (10, hash_decl_by_name, hash_decl_name_eq, NULL);
+}
+
+void
+free_static_inline_table ()
+{
+ htab_delete (static_inline_decls);
+}
+
+void
+remember_function_decl(tree fndecl)
+{
+ /* Check if this is a static inline function. */
+ if (DECL_DECLARED_INLINE_P(fndecl) && !TREE_PUBLIC(fndecl))
+ {
+ tree *slot;
+
+ slot = (tree *)htab_find_slot (static_inline_decls, fndecl, INSERT);
+ *slot = fndecl;
+ }
+}
+
/* Throw a fatal error if a dynval is not allowed in a before-advice
call. */
static void
The new nodes get stored in arglist. GIMPLE statements that must
be inserted before the call are put in the pre_stmts list. */
static gimple
-build_gcc_call (const char *func_name, tree return_type,
+build_gcc_call (const char *func_name, tree return_type, tree block,
enum aop_insert_location location, VEC(gimple, heap) *pre_stmts,
va_list argp)
{
tree func_type;
tree func_decl;
+ tree inline_decl;
gimple func_call;
arg_list = VEC_alloc (tree, heap, 2);
func_type = build_function_type (return_type, argtype_list);
func_decl = build_fn_decl (func_name, func_type);
+
+ /* Wait, have we encountered a static inline decl with this same
+ name? */
+ inline_decl = htab_find(static_inline_decls, func_decl);
+ if (inline_decl != NULL)
+ func_decl = inline_decl;
+
func_call = gimple_build_call_vec (func_decl, arg_list);
+ /* GCC caveat, if there's a chance this call will be inlined, make
+ sure it has a block. */
+ if (func_decl == inline_decl)
+ gimple_set_block(func_call, block);
+
VEC_free (tree, heap, arg_list);
remember_advice (func_call);
va_list argp;
gimple func_call;
struct aop_pointcut *pc;
+ tree block = NULL;
VEC(gimple, heap) *pre_stmts;
pc = jp->pc;
jp->is_prepared = true;
}
+ if (jp->stmt != NULL)
+ block = gimple_block(jp->stmt);
+
pre_stmts = VEC_alloc (gimple, heap, 2);
va_start (argp, location);
- func_call = build_gcc_call (func_name, void_type_node, location, pre_stmts,
- argp);
+ func_call = build_gcc_call (func_name, void_type_node, block, location,
+ pre_stmts, argp);
va_end (argp);
va_start (argp, location);
{
va_list argp;
gimple func_call;
+ tree block = NULL;
struct aop_pointcut *pc;
VEC(gimple, heap) *pre_stmts;
else if (is_current_func_duplicated())
fatal_error ("(InterAspect) Cannot duplicate a function more than once.");
+ if (jp->stmt != NULL)
+ block = gimple_block(jp->stmt);
+
pre_stmts = VEC_alloc (gimple, heap, 2);
va_start (argp, func_name);
- func_call = build_gcc_call (func_name, integer_type_node, AOP_INSERT_BEFORE,
- pre_stmts, argp);
+ func_call = build_gcc_call (func_name, integer_type_node, block,
+ AOP_INSERT_BEFORE, pre_stmts, argp);
va_end (argp);
va_start (argp, func_name);