This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: adding GGC events for plugins.
Diego Novillo wrote:
Some comments in addition to what's been suggested earlier in the
thread:
Thanks to Diego Novillo & Rafael Espindola & Brad Hards & Paolo Bonzini
for their feedback. Here is my improved patch (including updated
documentation about plugins).
This is a patch to trunk rev147442
gcc/ChangeLog:
2009-05-12 Basile Starynkevitch <basile@starynkevitch.net>
* doc/plugins.texi (Loading Plugins): Typo: -ldl instead of -ld
(Plugin initialization): updated plugin_init description.
(Plugin callbacks): updated plugin_event description, and added
PLUGIN_INFO, PLUGIN_GGC_START, PLUGIN_GGC_MARKING, PLUGIN_GGC_END,
PLUGIN_REGISTER_GGC_ROOTS. Documented the pseudo-events.
(Interacting with the GCC Garbage Collector) Added section.
(Giving information about a plugin) Added section.
* gcc-plugin.h (enum plugin_event): Added PLUGIN_GGC_START,
PLUGIN_GGC_MARKING, PLUGIN_GGC_END, PLUGIN_REGISTER_GGC_ROOTS and
updated comment of register_callback.
* ggc.h: Declared ggc_register_root_tab.
* ggc-common.c: including "plugin.h" & "vec.h".
(extra_root_vec): new static vector.
(ggc_register_root_tab): added new function.
(ggc_mark_roots): scan the extra_root_vec if needed, and do the
PLUGIN_GGC_MARKING callback.
* ggc-zone.c (ggc_collect): call PLUGIN_GGC_START & PLUGIN_GGC_END
callbacks.
* ggc-page.c (ggc_collect): likewise.
* plugin.c (plugin_event_name, register_callback)
(invoke_plugin_callbacks): handle PLUGIN_GGC_START,
PLUGIN_GGC_MARKING, PLUGIN_GGC_END, PLUGIN_REGISTER_GGC_ROOTS.
* Makefile.in: plugin.o also depends upon $(GGC_H) and
ggc-common.h depends upon plugin.h & vec.h.
gcc/testsuite/ChangeLog:
2009-05-12 Basile Starynkevitch <basile@starynkevitch.net>
* gcc.dg/plugin/ggcplug-test-1.c: Added new file.
* gcc.dg/plugin/ggcplug.c: Added new file.
* gcc.dg/plugin/plugin.exp: added ggcplug test.
Bootstraped on x86_64-linux-gnu (Debian/Sid/AMD64) with enable-languages=c.
Ok to commit ?
Respectful regards.
--
Basile STARYNKEVITCH http://starynkevitch.net/Basile/
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359
8, rue de la Faiencerie, 92340 Bourg La Reine, France
*** opinions {are only mines, sont seulement les miennes} ***
Index: gcc/doc/plugins.texi
===================================================================
--- gcc/doc/plugins.texi (revision 147442)
+++ gcc/doc/plugins.texi (working copy)
@@ -9,7 +9,7 @@
@section Loading Plugins
-Plugins are supported on platforms that support @option{-ld
+Plugins are supported on platforms that support @option{-ldl
-rdynamic}. They are loaded by the compiler using @code{dlopen}
and invoked at pre-determined locations in the compilation
process.
@@ -42,6 +42,7 @@ the parser. The arguments to @code{plugin_init} a
@itemize @bullet
@item @code{plugin_name}: Name of the plugin.
+@item @code{struct plugin_gcc_version*}: Data giving the GCC version.
@item @code{argc}: Number of arguments specified with @option{-fplugin-arg-...}.
@item @code{argv}: Array of @code{argc} key-value pairs.
@end itemize
@@ -49,6 +50,25 @@ the parser. The arguments to @code{plugin_init} a
If initialization fails, @code{plugin_init} must return a non-zero
value. Otherwise, it should return 0.
+The version of the GCC compiler loading the plugin is described by the
+following structure:
+
+@smallexample
+struct plugin_gcc_version
+@{
+ const char *basever;
+ const char *datestamp;
+ const char *devphase;
+ const char *revision;
+ const char *configuration_arguments;
+@};
+@end smallexample
+
+The function @code{plugin_default_version_check} takes two pointers to
+such structure and compare them field by field. It can be used by the
+plugin's @code{plugin_init} function.
+
+
@subsection Plugin callbacks
Callback functions have the following prototype:
@@ -71,13 +91,20 @@ enum plugin_event
PLUGIN_FINISH_UNIT, /* Useful for summary processing. */
PLUGIN_CXX_CP_PRE_GENERICIZE, /* Allows to see low level AST in C++ FE. */
PLUGIN_FINISH, /* Called before GCC exits. */
+ PLUGIN_INFO, /* Information about the plugin. */
+ PLUGIN_GGC_START, /* Called at start of GCC Garbage Collection. */
+ PLUGIN_GGC_MARKING, /* Extend the GGC marking. */
+ PLUGIN_GGC_END, /* Called at end of GGC. */
+ PLUGIN_REGISTER_GGC_ROOTS, /* Register an extra GGC root table. */
PLUGIN_EVENT_LAST /* Dummy event used for indexing callback
array. */
@};
@end smallexample
-To register a callback, the plugin calls @code{register_callback} with the arguments:
+To register a callback, the plugin calls @code{register_callback} with
+the arguments:
+
@itemize
@item @code{char *name}: Plugin name.
@item @code{enum plugin_event event}: The event code.
@@ -85,6 +112,9 @@ enum plugin_event
@item @code{void *user_data}: Pointer to plugin-specific data.
@end itemize
+For the PLUGIN_PASS_MANAGER_SETUP, PLUGIN_INFO, and
+PLUGIN_REGISTER_GGC_ROOTS pseudo-events the @code{callback} should be
+null, and the @code{user_data} is specific.
@section Interacting with the pass manager
@@ -135,3 +165,45 @@ plugin_init (const char *plugin_name, int argc, st
...
@}
@end smallexample
+
+
+@section Interacting with the GCC Garbage Collector
+
+Some plugins may want to be informed when GGC (the GCC Garbage
+Collector) is running. They can register callbacks for the
+@code{PLUGIN_GGC_START} and @code{PLUGIN_GGC_END} events (for which
+the callback is called with a null @code{gcc_data}) to be notified of
+the start or end of the GCC garbage collection.
+
+Some plugins may need to have GGC mark additional data. This can be
+done by registering a callback (called with a null @code{gcc_data})
+for the @code{PLUGIN_GGC_MARKING} event. Such callbacks can call the
+@code{ggc_set_mark} routine, preferably thru the @code{ggc_mark}
+macro.
+
+Some plugins may need to add extra GGC root tables, e.g. to handle
+their own @code{GTY}-ed data. This can be done with the
+@code{PLUGIN_REGISTER_GGC_ROOTS} pseudo-event with a null callback and the
+extra root table as data.
+
+You should understand the details of memory management inside GCC
+before using @code{PLUGIN_GGC_MARKING} or
+@code{PLUGIN_REGISTER_GGC_ROOTS}.
+
+
+@section Giving information about a plugin
+
+A plugin should give some information to the user about itself. This
+uses the following structure:
+
+@smallexample
+struct plugin_info
+@{
+ const char *version;
+ const char *help;
+@};
+@end smallexample
+
+Such a structure is passed as the @code{user_data} by the plugin's
+init routine using @code{register_callback} with the
+@code{PLUGIN_INFO} pseudo-event and a null callback.
Index: gcc/testsuite/gcc.dg/plugin/ggcplug-test-1.c
===================================================================
--- gcc/testsuite/gcc.dg/plugin/ggcplug-test-1.c (revision 0)
+++ gcc/testsuite/gcc.dg/plugin/ggcplug-test-1.c (revision 0)
@@ -0,0 +1,12 @@
+/* Test the ggcplug plugin. */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+int main()
+{
+ int i=0, j=0;
+ for (i= 0; i<1000; i++)
+ if (i%8 == 0)
+ j++;
+ return 0;
+}
Index: gcc/testsuite/gcc.dg/plugin/plugin.exp
===================================================================
--- gcc/testsuite/gcc.dg/plugin/plugin.exp (revision 147442)
+++ gcc/testsuite/gcc.dg/plugin/plugin.exp (working copy)
@@ -47,7 +47,9 @@ load_lib plugin-support.exp
# Specify the plugin source file and the associated test files in a list.
# plugin_test_list={ {plugin1 test1 test2 ...} {plugin2 test1 ...} ... }
set plugin_test_list [list \
- { selfassign.c self-assign-test-1.c self-assign-test-2.c } ]
+ { selfassign.c self-assign-test-1.c self-assign-test-2.c } \
+ { ggcplug.c ggcplug-test-1.c } \
+]
foreach plugin_test $plugin_test_list {
# Replace each source file with its full-path name
Index: gcc/testsuite/gcc.dg/plugin/ggcplug.c
===================================================================
--- gcc/testsuite/gcc.dg/plugin/ggcplug.c (revision 0)
+++ gcc/testsuite/gcc.dg/plugin/ggcplug.c (revision 0)
@@ -0,0 +1,106 @@
+/* This plugin tests the GGC related plugin events. */
+/* { dg-options "-O" } */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "gcc-plugin.h"
+
+
+/* The initialization routine exposed to and called by GCC. The spec of this
+ function is defined in gcc/gcc-plugin.h.
+
+ Note that this function needs to be named exactly "plugin_init". */
+
+
+/* our callback is the same for all PLUGIN_GGC_START,
+ PLUGIN_GGC_MARKING, PLUGIN_GGC_END events; it just increments the
+ user_data which is an int */
+static void increment_callback (void *gcc_data, void *user_data);
+
+/* our counters are user_data */
+static int our_ggc_start_counter;
+static int our_ggc_end_counter;
+static int our_ggc_marking_counter;
+
+/* our empty GGC extra root table */
+static const struct ggc_root_tab our_xtratab[] = {
+ LAST_GGC_ROOT_TAB
+};
+
+int
+plugin_init (const char *plugin_name, struct plugin_gcc_version *version,
+ int argc, struct plugin_argument *argv)
+{
+ if (!plugin_default_version_check (version, version))
+ return 1;
+ /* Process the plugin arguments. This plugin takes the following arguments:
+ count-ggc-start count-ggc-end count-ggc-mark */
+ for (i = 0; i < argc; ++i)
+ {
+ if (!strcmp (argv[i].key, "count-ggc-start"))
+ {
+ if (argv[i].value)
+ warning (0, G_ ("option '-fplugin-arg-%s-count-ggc-start=%s'"
+ " ignored (superfluous '=%s')"),
+ plugin_name, argv[i].value, argv[i].value);
+ else
+ register_callback ("ggcplug",
+ PLUGIN_GGC_START,
+ increment_callback,
+ (void *) &our_ggc_start_counter);
+ }
+ else if (!strcmp (argv[i].key, "count-ggc-end"))
+ {
+ if (argv[i].value)
+ warning (0, G_ ("option '-fplugin-arg-%s-count-ggc-end=%s'"
+ " ignored (superfluous '=%s')"),
+ plugin_name, argv[i].value, argv[i].value);
+ else
+ register_callback ("ggcplug",
+ PLUGIN_GGC_END,
+ increment_callback,
+ (void *) &our_ggc_end_counter);
+ }
+ else if (!strcmp (argv[i].key, "count-ggc-mark"))
+ {
+ if (argv[i].value)
+ warning (0, G_ ("option '-fplugin-arg-%s-count-ggc-mark=%s'"
+ " ignored (superfluous '=%s')"),
+ plugin_name, argv[i].value, argv[i].value);
+ else
+ register_callback ("ggcplug",
+ PLUGIN_GGC_MARKING,
+ increment_callback,
+ (void *) &our_ggc_marking_counter);
+ }
+ else if (!strcmp (argv[i].key, "test-extra-root"))
+ {
+ if (argv[i].value)
+ warning (0, G_ ("option '-fplugin-arg-%s-test-extra-root=%s'"
+ " ignored (superfluous '=%s')"),
+ plugin_name, argv[i].value, argv[i].value);
+ else
+ register_callback ("ggcplug",
+ PLUGIN_REGISTER_GGC_ROOTS,
+ NULL,
+ (void *) our_xtratab);
+ }
+ }
+}
+
+static void
+increment_callback (void *gcc_data, void *user_data)
+{
+ int *usercountptr = (int *) user_data;
+ gcc_assert (!gcc_data);
+ gcc_assert (user_data);
+ (*usercountptr)++;
+}
Index: gcc/ggc.h
===================================================================
--- gcc/ggc.h (revision 147442)
+++ gcc/ggc.h (working copy)
@@ -1,7 +1,8 @@
/* Garbage collection for the GNU compiler.
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007,
+ 2008, 2009 Free Software Foundation, Inc.
+
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
@@ -270,6 +271,10 @@ extern const char *ggc_alloc_string (const char *c
function is called, not during allocations. */
extern void ggc_collect (void);
+/* Register an additional root table. This can be useful for some
+ plugins. Does nothing if the passed pointer is null. */
+extern void ggc_register_root_tab (const struct ggc_root_tab *);
+
/* Return the number of bytes allocated at the indicated address. */
extern size_t ggc_get_size (const void *);
Index: gcc/gcc-plugin.h
===================================================================
--- gcc/gcc-plugin.h (revision 147442)
+++ gcc/gcc-plugin.h (working copy)
@@ -28,7 +28,11 @@ enum plugin_event
PLUGIN_FINISH_UNIT, /* Useful for summary processing. */
PLUGIN_CXX_CP_PRE_GENERICIZE, /* Allows to see low level AST in C++ FE. */
PLUGIN_FINISH, /* Called before GCC exits. */
- PLUGIN_INFO, /* Information about the plugin */
+ PLUGIN_INFO, /* Information about the plugin. */
+ PLUGIN_GGC_START, /* Called at start of GCC Garbage Collection. */
+ PLUGIN_GGC_MARKING, /* Extend the GGC marking. */
+ PLUGIN_GGC_END, /* Called at end of GGC. */
+ PLUGIN_REGISTER_GGC_ROOTS, /* Register an extra GGC root table. */
PLUGIN_EVENT_LAST /* Dummy event used for indexing callback
array. */
};
@@ -116,8 +120,13 @@ typedef void (*plugin_callback_func) (void *gcc_da
PLUGIN_NAME - display name for this plugin
EVENT - which event the callback is for
CALLBACK - the callback to be called at the event
- USER_DATA - plugin-provided data */
+ USER_DATA - plugin-provided data
+ This is also called without a callback routine for the
+ PLUGIN_PASS_MANAGER_SETUP, PLUGIN_INFO, PLUGIN_REGISTER_GGC_ROOTS
+ pseudo-events, with a specific user_data.
+ */
+
extern void register_callback (const char *plugin_name,
enum plugin_event event,
plugin_callback_func callback,
Index: gcc/ggc-common.c
===================================================================
--- gcc/ggc-common.c (revision 147442)
+++ gcc/ggc-common.c (working copy)
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "hosthooks.h"
#include "hosthooks-def.h"
+#include "plugin.h"
+#include "vec.h"
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
@@ -86,6 +88,33 @@ ggc_htab_delete (void **slot, void *info)
return 1;
}
+
+/* This extra vector of dynamically registered root_tab-s is used by
+ ggc_mark_roots and gives the ability to dynamically add new GGC root
+ tables, for instance from some plugins; this vector is a heap one
+ [since it is used by GGC internally!] */
+typedef const struct ggc_root_tab* const_ggc_root_tab_t;
+DEF_VEC_P(const_ggc_root_tab_t);
+DEF_VEC_ALLOC_P(const_ggc_root_tab_t, heap);
+static VEC(const_ggc_root_tab_t, heap) *extra_root_vec;
+
+
+/* Dynamically register a new GGC root table. This is useful for
+ plugins */
+void
+ggc_register_root_tab (const struct ggc_root_tab* rt)
+{
+ if (!rt)
+ return;
+ if (!extra_root_vec)
+ {
+ int vlen = 32;
+ extra_root_vec = VEC_alloc (const_ggc_root_tab_t, heap, vlen);
+ }
+ VEC_safe_push (const_ggc_root_tab_t, heap, extra_root_vec, rt);
+}
+
+
/* Iterate through all registered roots and mark each element. */
void
@@ -106,6 +135,19 @@ ggc_mark_roots (void)
for (i = 0; i < rti->nelt; i++)
(*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
+ if (extra_root_vec && VEC_length(const_ggc_root_tab_t,extra_root_vec)>0)
+ {
+ const_ggc_root_tab_t rtp = NULL;
+ for (i=0;
+ VEC_iterate(const_ggc_root_tab_t, extra_root_vec, i, rtp);
+ i++)
+ {
+ for (rti = rtp; rti->base != NULL; rti++)
+ for (i = 0; i < rti->nelt; i++)
+ (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
+ }
+ }
+
if (ggc_protect_identifiers)
ggc_mark_stringpool ();
@@ -123,6 +165,9 @@ ggc_mark_roots (void)
if (! ggc_protect_identifiers)
ggc_purge_stringpool ();
+
+ /* Some plugins may call ggc_set_mark from here. */
+ invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL);
}
/* Allocate a block of memory, then clear it. */
Index: gcc/ggc-zone.c
===================================================================
--- gcc/ggc-zone.c (revision 147442)
+++ gcc/ggc-zone.c (working copy)
@@ -2029,6 +2029,8 @@ ggc_collect (void)
}
}
+ invoke_plugin_callbacks (PLUGIN_GGC_START, NULL);
+
/* Start by possibly collecting the main zone. */
main_zone.was_collected = false;
marked |= ggc_collect_1 (&main_zone, true);
@@ -2093,6 +2095,8 @@ ggc_collect (void)
}
}
+ invoke_plugin_callbacks (PLUGIN_GGC_END, NULL);
+
timevar_pop (TV_GC);
}
Index: gcc/ggc-page.c
===================================================================
--- gcc/ggc-page.c (revision 147442)
+++ gcc/ggc-page.c (working copy)
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "params.h"
#include "tree-flow.h"
+#include "plugin.h"
/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a
file open. Prefer either to valloc. */
@@ -1937,6 +1938,8 @@ ggc_collect (void)
/* Indicate that we've seen collections at this context depth. */
G.context_depth_collections = ((unsigned long)1 << (G.context_depth + 1)) - 1;
+ invoke_plugin_callbacks (PLUGIN_GGC_START, NULL);
+
clear_marks ();
ggc_mark_roots ();
#ifdef GATHER_STATISTICS
@@ -1948,6 +1951,8 @@ ggc_collect (void)
G.allocated_last_gc = G.allocated;
+ invoke_plugin_callbacks (PLUGIN_GGC_END, NULL);
+
timevar_pop (TV_GC);
if (!quiet_flag)
Index: gcc/plugin.c
===================================================================
--- gcc/plugin.c (revision 147442)
+++ gcc/plugin.c (working copy)
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "plugin.h"
#include "timevar.h"
+#include "ggc.h"
+
#ifdef ENABLE_PLUGIN
#include "plugin-version.h"
#endif
@@ -51,6 +53,10 @@ const char *plugin_event_name[] =
"PLUGIN_CXX_CP_PRE_GENERICIZE",
"PLUGIN_FINISH",
"PLUGIN_INFO",
+ "PLUGIN_GGC_START",
+ "PLUGIN_GGC_MARKING",
+ "PLUGIN_GGC_END",
+ "PLUGIN_REGISTER_GGC_ROOTS",
"PLUGIN_EVENT_LAST"
};
@@ -485,14 +491,23 @@ register_callback (const char *plugin_name,
switch (event)
{
case PLUGIN_PASS_MANAGER_SETUP:
+ gcc_assert (!callback);
register_pass (plugin_name, (struct plugin_pass *) user_data);
break;
case PLUGIN_INFO:
+ gcc_assert (!callback);
register_plugin_info (plugin_name, (struct plugin_info *) user_data);
break;
+ case PLUGIN_REGISTER_GGC_ROOTS:
+ gcc_assert (!callback);
+ ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
+ break;
case PLUGIN_FINISH_TYPE:
case PLUGIN_FINISH_UNIT:
case PLUGIN_CXX_CP_PRE_GENERICIZE:
+ case PLUGIN_GGC_START:
+ case PLUGIN_GGC_MARKING:
+ case PLUGIN_GGC_END:
case PLUGIN_FINISH:
{
struct callback_info *new_callback;
@@ -535,6 +550,9 @@ invoke_plugin_callbacks (enum plugin_event event,
case PLUGIN_FINISH_UNIT:
case PLUGIN_CXX_CP_PRE_GENERICIZE:
case PLUGIN_FINISH:
+ case PLUGIN_GGC_START:
+ case PLUGIN_GGC_MARKING:
+ case PLUGIN_GGC_END:
{
/* Iterate over every callback registered with this event and
call it. */
@@ -546,6 +564,7 @@ invoke_plugin_callbacks (enum plugin_event event,
case PLUGIN_PASS_MANAGER_SETUP:
case PLUGIN_EVENT_LAST:
+ case PLUGIN_REGISTER_GGC_ROOTS:
default:
gcc_assert (false);
}
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in (revision 147442)
+++ gcc/Makefile.in (working copy)
@@ -2033,8 +2033,9 @@ gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H)
$(CPP_ID_DATA_H) tree-chrec.h $(CFGLAYOUT_H) $(EXCEPT_H) output.h \
$(CFGLOOP_H)
-ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \
- $(HASHTAB_H) $(TOPLEV_H) $(PARAMS_H) hosthooks.h $(HOSTHOOKS_DEF_H)
+ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+ $(GGC_H) $(HASHTAB_H) $(TOPLEV_H) $(PARAMS_H) hosthooks.h \
+ $(HOSTHOOKS_DEF_H) vec.h plugin.h
ggc-page.o: ggc-page.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
$(FLAGS_H) $(TOPLEV_H) $(GGC_H) $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) $(TREE_FLOW_H)
@@ -2481,7 +2482,7 @@ passes.o : passes.c $(CONFIG_H) $(SYSTEM_H) corety
gt-passes.h $(DF_H) $(PREDICT_H)
plugin.o : plugin.c $(PLUGIN_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
- $(TOPLEV_H) $(TREE_H) $(TREE_PASS_H) intl.h $(PLUGIN_VERSION_H)
+ $(TOPLEV_H) $(TREE_H) $(TREE_PASS_H) intl.h $(PLUGIN_VERSION_H) $(GGC_H)
main.o : main.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TOPLEV_H)