Store prototype for each advice function.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Wed, 14 Jul 2010 23:57:29 +0000 (19:57 -0400)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Wed, 14 Jul 2010 23:57:29 +0000 (19:57 -0400)
src/Makefile.am
src/aop-header.c [new file with mode: 0644]
src/aop-header.h [new file with mode: 0644]
src/aop-main.c
src/aop-type.c
src/aop-type.h
src/aop-weave.c

index e353f15c5570aed850b9b4c8edba05b7751bb43c..de2564c0d8cc4088ed69b3433e7cfb6af7d3270c 100644 (file)
@@ -1,5 +1,6 @@
 lib_LTLIBRARIES = libinteraspect.la
-libinteraspect_la_SOURCES = aop-pc-assign.c aop-main.c aop-type.c aop-weave.c aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c
+libinteraspect_la_SOURCES = aop-pc-assign.c aop-main.c aop-type.c aop-weave.c \
+       aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c aop-header.c
 libinteraspect_la_CFLAGS = -Wall -Werror -fvisibility=hidden -prefer-pic
 libinteraspect_la_LDFLAGS = -static -prefer-pic -version-info 1:0:0
 libinteraspect_la_CPPFLAGS = -DHAVE_CONFIG_H -DIN_GCC -I$(gcc_includes)
diff --git a/src/aop-header.c b/src/aop-header.c
new file mode 100644 (file)
index 0000000..9ca2c61
--- /dev/null
@@ -0,0 +1,216 @@
+/* This program is free software: you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation, either version 3 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* aop-header.c: Functions for storing the advice function prototypes
+   we have seen and later outputing those prototypes to an
+   auto-generated header file. */
+
+/* Whether we want them or not (we don't), Autoconf _insists_ on
+   defining these.  Since GCC's config.h (which we must include) also
+   defines them, we have to undef them here. */
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include <locale.h>
+#include <stdarg.h>
+
+#include <config.h>
+#include <system.h>
+#include <tree.h>
+#include <hashtab.h>
+#include <toplev.h>
+
+#include "aop.h"
+#include "aop-dynval.h"
+#include "aop-header.h"
+#include "aop-type.h"
+
+/* An aop_prototype struct represents the prototype of an advice
+   function, including its name, return type and parameters. */
+struct aop_prototype {
+  /* Users should not create multiple prototypes with the same name
+     but different return/parameter types, but if they do, we can
+     chain them together in this list. */
+  struct aop_prototype *next;
+
+  /* True if the prototype has return type int.  False if the
+     prototype has a void return type. */
+  bool has_return_value;
+
+  const char *name;
+
+  int num_params;
+  const struct aop_type *param_types[];
+};
+
+/* This table matches function name to function prototype.  Where
+   there are multiple prototypes with the same name (an error case),
+   those prototypes are chained together in a linked list. */
+static htab_t prototype_table = NULL;
+
+/* This is the equality function that the hashtable uses to determine
+   if a prototype entry in the table matches a key. */
+static int
+htab_str_eq (const void *table_entry, const void *key)
+{
+  const struct aop_prototype *prototype =
+    (const struct aop_prototype *)table_entry;
+
+  return (strcmp (prototype->name, key) == 0);
+}
+
+/* Return true if a prototype has the same return value and parameters
+   as a potential new prototype. */
+static bool
+is_compatible_prototype (struct aop_prototype *prototype,
+                        bool has_return_value, int num_params,
+                        const struct aop_type *param_types[])
+{
+  int i;
+
+  /* The prototypes do not match if one returns a value and the other
+     does not. */
+  if ((prototype->has_return_value && !has_return_value) ||
+      (!prototype->has_return_value && has_return_value))
+    return false;
+
+  if (prototype->num_params != num_params)
+    return false;
+
+  for (i = 0; i < num_params; i++)
+    {
+      if (!are_types_equal (prototype->param_types[i], param_types[i]))
+       return false;
+    }
+
+  /* These prototypes match. */
+  return true;
+}
+
+static void
+get_param_types (va_list argp, int num_params,
+                const struct aop_type *param_types[])
+{
+  int i;
+  enum aop_argkind kind;
+  struct aop_dynval *dv;
+
+  for (i = 0; i < num_params; i++)
+    {
+      kind = va_arg (argp, enum aop_argkind);
+      switch (kind)
+       {
+       case ATA_STR_CST:
+         aop_assert (0);
+         break;
+       case ATA_INT_CST:
+         va_arg (argp, int);
+         param_types[i] = aop_t_all_signed ();
+         break;
+       case ATA_FLOAT_CST:
+         va_arg (argp, double);
+         param_types[i] = aop_t_all_fp ();
+         break;
+       case ATA_VOIDP_CST:
+         va_arg (argp, void *);
+         param_types[i] = aop_t_all_pointer ();
+         break;
+       case ATA_DYNVAL:
+         dv = va_arg (argp, struct aop_dynval *);
+         param_types[i] = dv->type;
+         break;
+       default:
+         aop_assert (0);
+       }
+    }
+
+  aop_assert (va_arg (argp, enum aop_argkind) == AOP_TERM_ARG);
+}
+
+/* If there is no entry in the list of advice function prototypes for
+   this advice function, create one.  If a prototype already exists
+   with conflicting types, issue a warning. */
+void
+insert_prototype (bool has_return_value, const char *name, int num_params,
+                 va_list argp)
+{
+  size_t param_types_size;
+  const struct aop_type **param_types;
+
+  struct aop_prototype **hash_slot;
+  struct aop_prototype *prototype;
+
+  param_types_size = num_params * sizeof (const struct aop_type *);
+  param_types = alloca (param_types_size);
+  get_param_types (argp, num_params, param_types);
+
+  /* Check the hash table for a prototype with this name. */
+  hash_slot =
+    (struct aop_prototype **)htab_find_slot (prototype_table, name, INSERT);
+  if (*hash_slot != NULL)
+    {
+      /* We already have at least one prototype with this name.  Make
+        sure one of them is compatible. */
+      while (*hash_slot != NULL)
+       {
+         prototype = *hash_slot;
+
+         if (is_compatible_prototype (prototype, has_return_value, num_params,
+                                      param_types))
+           {
+             /* Found one!  Nothing else to do. */
+             return;
+           }
+
+         hash_slot = &prototype->next;
+       }
+
+      /* None of the prototypes we have already seen matches this one.
+        First, we issue a warning. */
+      warning (0, "(InterAspect) Calls to advice function %s with different "
+              "prototypes", name);
+
+      /* Then we fall through to the code to allocate and initialize a
+        new prototype object. */
+    }
+
+  /* Allocate the new prototype and insert it in the hash table (or in
+     the linked list if we happened to find a hash table entry
+     already). */
+  prototype = xmalloc (sizeof (struct aop_prototype *) + 
+                      (num_params * sizeof (const struct aop_type *)));
+  *hash_slot = prototype;
+
+  prototype->has_return_value = has_return_value;
+  prototype->name = xstrdup (name);
+  prototype->num_params = num_params;
+  memcpy (prototype->param_types, param_types, param_types_size);
+}
+
+void
+init_prototype_table()
+{
+  prototype_table = htab_create_alloc (16, htab_hash_string, htab_str_eq, NULL,
+                                      xcalloc, free);
+}
+
+void
+free_prototype_table()
+{
+  /* TODO: Free the contents as well. */
+  htab_delete (prototype_table);
+}
diff --git a/src/aop-header.h b/src/aop-header.h
new file mode 100644 (file)
index 0000000..d21d4bb
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __AOP_HEADER_H__
+#define __AOP_HEADER_H__
+
+/* This program is free software: you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation, either version 3 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This is a private header.  Do not include it in source file for
+   client plug-ins. */
+
+void insert_prototype (bool has_return_value, const char *name, int num_params,
+                      va_list argp);
+
+void init_prototype_table();
+void free_prototype_table();
+
+#endif
index 0acac47c55561763c2d1fc0d8b9cb2c7c5da4850..83c76f53f3d05ecfc688b869e90b7a1fffca8f2c 100644 (file)
@@ -51,6 +51,7 @@
 #include <c-common.h>
 
 #include "aop.h"
+#include "aop-header.h"
 #include "aop-pointcut.h"
 
 //#define PAUSE_ON_START
@@ -159,6 +160,7 @@ cleanup_passes ()
 static void
 aop_cleanup (void *event_date, void *data)
 {
+  free_prototype_table ();
   cleanup_passes ();
 }
 
@@ -186,6 +188,8 @@ plugin_init (struct plugin_name_args *plugin_info,
 
   aop_plugin_name = plugin_info->base_name;
 
+  init_prototype_table ();
+
   /* Register our cleanup function. */
   register_callback (aop_plugin_name, PLUGIN_FINISH, aop_cleanup, NULL);
 
index f0b4aefd9ebe7316e38591d6fe14069173ce4d84..52eb02237858668f244375d62797354cb3c07f66 100644 (file)
@@ -110,3 +110,10 @@ does_type_match (tree gcc_type, const struct aop_type *aop_type)
 
   aop_assert (0);
 }
+
+/* Return true if two aop_type objects are equal. */
+bool
+are_types_equal (const struct aop_type *a, const struct aop_type *b)
+{
+  return (a == b);
+}
index 7b88c8bb70a3f315285326e811d01a825ced4ace..aa8d3799c73194924e4e8ff0bbb0a3028b8add87 100644 (file)
@@ -36,5 +36,6 @@ struct aop_type {
 };
 
 bool does_type_match (tree gcc_type, const struct aop_type *aop_type);
+bool are_types_equal (const struct aop_type *a, const struct aop_type *b);
 
 #endif
index 492866699cc2541d1f50b45b386ea87a78918de7..c8edaa8d9eb12289942faf200b2989d8a38b258d 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "aop.h"
 #include "aop-dynval.h"
+#include "aop-header.h"
 #include "aop-pointcut.h"
 
 /* Throw a fatal error if a dynval is not allowed in a before-advice
@@ -255,10 +256,14 @@ aop_insert_advice (struct aop_joinpoint *jp, const char *func_name,
   va_start (argp, location);
   func_call = build_gcc_call (func_name, void_type_node, location, argp);
   va_end (argp);
+
+  va_start (argp, location);
+  insert_prototype (false /* void return type */, func_name,
+                   gimple_call_num_args (func_call), argp);
+  va_end (argp);
   
   if(location == AOP_INSERT_BEFORE)
     pc->insert_before(jp, func_call);
   else if(location == AOP_INSERT_AFTER)
     pc->insert_after(jp, func_call);
-
 }