--- /dev/null
+/* 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);
+}