Rewrite registry.h

This rewrites registry.h, removing all the macros and replacing it
with relatively ordinary template classes.  The result is less code
than the previous setup.  It replaces large macros with a relatively
straightforward C++ class, and now manages its own cleanup.

The existing type-safe "key" class is replaced with the equivalent
template class.  This approach ended up requiring relatively few
changes to the users of the registry code in gdb -- code using the key
system just required a small change to the key's declaration.

All existing users of the old C-like API are now converted to use the
type-safe API.  This mostly involved changing explicit deletion
functions to be an operator() in a deleter class.

The old "save/free" two-phase process is removed, and replaced with a
single "free" phase.  No existing code used both phases.

The old "free" callbacks took a parameter for the enclosing container
object.  However, this wasn't truly needed and is removed here as
well.
This commit is contained in:
Tom Tromey
2020-10-18 11:38:10 -06:00
parent 8f83e7b926
commit 08b8a139c9
64 changed files with 664 additions and 1052 deletions

View File

@ -77,9 +77,33 @@ struct block_syms_iterator_object {
} \
} while (0)
/* This is called when an objfile is about to be freed.
Invalidate the block as further actions on the block would result
in bad data. All access to obj->symbol should be gated by
BLPY_REQUIRE_VALID which will raise an exception on invalid
blocks. */
struct blpy_deleter
{
void operator() (block_object *obj)
{
while (obj)
{
block_object *next = obj->next;
obj->block = NULL;
obj->objfile = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
};
extern PyTypeObject block_syms_iterator_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
static const struct objfile_data *blpy_objfile_data_key;
static const registry<objfile>::key<block_object, blpy_deleter>
blpy_objfile_data_key;
static PyObject *
blpy_iter (PyObject *self)
@ -269,10 +293,7 @@ blpy_dealloc (PyObject *obj)
if (block->prev)
block->prev->next = block->next;
else if (block->objfile)
{
set_objfile_data (block->objfile, blpy_objfile_data_key,
block->next);
}
blpy_objfile_data_key.set (block->objfile, block->next);
if (block->next)
block->next->prev = block->prev;
block->block = NULL;
@ -293,11 +314,10 @@ set_block (block_object *obj, const struct block *block,
if (objfile)
{
obj->objfile = objfile;
obj->next = ((block_object *)
objfile_data (objfile, blpy_objfile_data_key));
obj->next = blpy_objfile_data_key.get (objfile);
if (obj->next)
obj->next->prev = obj;
set_objfile_data (objfile, blpy_objfile_data_key, obj);
blpy_objfile_data_key.set (objfile, obj);
}
else
obj->next = NULL;
@ -404,40 +424,6 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
Py_RETURN_TRUE;
}
/* This function is called when an objfile is about to be freed.
Invalidate the block as further actions on the block would result
in bad data. All access to obj->symbol should be gated by
BLPY_REQUIRE_VALID which will raise an exception on invalid
blocks. */
static void
del_objfile_blocks (struct objfile *objfile, void *datum)
{
block_object *obj = (block_object *) datum;
while (obj)
{
block_object *next = obj->next;
obj->block = NULL;
obj->objfile = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
void _initialize_py_block ();
void
_initialize_py_block ()
{
/* Register an objfile "free" callback so we can properly
invalidate blocks when an object file is about to be
deleted. */
blpy_objfile_data_key
= register_objfile_data_with_cleanup (NULL, del_objfile_blocks);
}
int
gdbpy_initialize_blocks (void)
{

View File

@ -60,7 +60,35 @@ struct inferior_object
extern PyTypeObject inferior_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("inferior_object");
static const struct inferior_data *infpy_inf_data_key;
/* Deleter to clean up when an inferior is removed. */
struct infpy_deleter
{
void operator() (inferior_object *obj)
{
struct threadlist_entry *th_entry, *th_tmp;
if (!gdb_python_initialized)
return;
gdbpy_enter enter_py;
gdbpy_ref<inferior_object> inf_obj (obj);
inf_obj->inferior = NULL;
/* Deallocate threads list. */
for (th_entry = inf_obj->threads; th_entry != NULL;)
{
th_tmp = th_entry;
th_entry = th_entry->next;
delete th_tmp;
}
inf_obj->nthreads = 0;
}
};
static const registry<inferior>::key<inferior_object, infpy_deleter>
infpy_inf_data_key;
/* Require that INFERIOR be a valid inferior ID. */
#define INFPY_REQUIRE_VALID(Inferior) \
@ -221,7 +249,7 @@ inferior_to_inferior_object (struct inferior *inferior)
{
inferior_object *inf_obj;
inf_obj = (inferior_object *) inferior_data (inferior, infpy_inf_data_key);
inf_obj = infpy_inf_data_key.get (inferior);
if (!inf_obj)
{
inf_obj = PyObject_New (inferior_object, &inferior_object_type);
@ -234,7 +262,7 @@ inferior_to_inferior_object (struct inferior *inferior)
/* PyObject_New initializes the new object with a refcount of 1. This
counts for the reference we are keeping in the inferior data. */
set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
infpy_inf_data_key.set (inferior, inf_obj);
}
/* We are returning a new reference. */
@ -795,32 +823,6 @@ infpy_dealloc (PyObject *obj)
Py_TYPE (obj)->tp_free (obj);
}
/* Clear the INFERIOR pointer in an Inferior object and clear the
thread list. */
static void
py_free_inferior (struct inferior *inf, void *datum)
{
struct threadlist_entry *th_entry, *th_tmp;
if (!gdb_python_initialized)
return;
gdbpy_enter enter_py;
gdbpy_ref<inferior_object> inf_obj ((inferior_object *) datum);
inf_obj->inferior = NULL;
/* Deallocate threads list. */
for (th_entry = inf_obj->threads; th_entry != NULL;)
{
th_tmp = th_entry;
th_entry = th_entry->next;
delete th_tmp;
}
inf_obj->nthreads = 0;
}
/* Implementation of gdb.selected_inferior() -> gdb.Inferior.
Returns the current inferior object. */
@ -831,14 +833,6 @@ gdbpy_selected_inferior (PyObject *self, PyObject *args)
inferior_to_inferior_object (current_inferior ()).release ());
}
void _initialize_py_inferior ();
void
_initialize_py_inferior ()
{
infpy_inf_data_key =
register_inferior_data_with_cleanup (NULL, py_free_inferior);
}
int
gdbpy_initialize_inferior (void)
{

View File

@ -55,7 +55,20 @@ struct objfile_object
extern PyTypeObject objfile_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("objfile_object");
static const struct objfile_data *objfpy_objfile_data_key;
/* Clear the OBJFILE pointer in an Objfile object and remove the
reference. */
struct objfpy_deleter
{
void operator() (objfile_object *obj)
{
gdbpy_enter enter_py;
gdbpy_ref<objfile_object> object (obj);
object->objfile = nullptr;
}
};
static const registry<objfile>::key<objfile_object, objfpy_deleter>
objfpy_objfile_data_key;
/* Require that OBJF be a valid objfile. */
#define OBJFPY_REQUIRE_VALID(obj) \
@ -668,16 +681,6 @@ gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw)
/* Clear the OBJFILE pointer in an Objfile object and remove the
reference. */
static void
py_free_objfile (struct objfile *objfile, void *datum)
{
gdbpy_enter enter_py (objfile->arch ());
gdbpy_ref<objfile_object> object ((objfile_object *) datum);
object->objfile = NULL;
}
/* Return a new reference to the Python object of type Objfile
representing OBJFILE. If the object has already been created,
return it. Otherwise, create it. Return NULL and set the Python
@ -687,7 +690,7 @@ gdbpy_ref<>
objfile_to_objfile_object (struct objfile *objfile)
{
PyObject *result
= ((PyObject *) objfile_data (objfile, objfpy_objfile_data_key));
= (PyObject *) objfpy_objfile_data_key.get (objfile);
if (result == NULL)
{
gdbpy_ref<objfile_object> object
@ -698,21 +701,13 @@ objfile_to_objfile_object (struct objfile *objfile)
return NULL;
object->objfile = objfile;
set_objfile_data (objfile, objfpy_objfile_data_key, object.get ());
objfpy_objfile_data_key.set (objfile, object.get ());
result = (PyObject *) object.release ();
}
return gdbpy_ref<>::new_reference (result);
}
void _initialize_py_objfile ();
void
_initialize_py_objfile ()
{
objfpy_objfile_data_key
= register_objfile_data_with_cleanup (NULL, py_free_objfile);
}
int
gdbpy_initialize_objfile (void)
{

View File

@ -57,7 +57,30 @@ struct pspace_object
extern PyTypeObject pspace_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pspace_object");
static const struct program_space_data *pspy_pspace_data_key;
/* Clear the PSPACE pointer in a Pspace object and remove the reference. */
struct pspace_deleter
{
void operator() (pspace_object *obj)
{
/* This is a fiction, but we're in a nasty spot: The pspace is in the
process of being deleted, we can't rely on anything in it. Plus
this is one time when the current program space and current inferior
are not in sync: All inferiors that use PSPACE may no longer exist.
We don't need to do much here, and since "there is always an inferior"
using target_gdbarch suffices.
Note: We cannot call get_current_arch because it may try to access
the target, which may involve accessing data in the pspace currently
being deleted. */
struct gdbarch *arch = target_gdbarch ();
gdbpy_enter enter_py (arch);
gdbpy_ref<pspace_object> object (obj);
object->pspace = NULL;
}
};
static const registry<program_space>::key<pspace_object, pspace_deleter>
pspy_pspace_data_key;
/* Require that PSPACE_OBJ be a valid program space ID. */
#define PSPY_REQUIRE_VALID(pspace_obj) \
@ -463,27 +486,6 @@ pspy_is_valid (PyObject *o, PyObject *args)
/* Clear the PSPACE pointer in a Pspace object and remove the reference. */
static void
py_free_pspace (struct program_space *pspace, void *datum)
{
/* This is a fiction, but we're in a nasty spot: The pspace is in the
process of being deleted, we can't rely on anything in it. Plus
this is one time when the current program space and current inferior
are not in sync: All inferiors that use PSPACE may no longer exist.
We don't need to do much here, and since "there is always an inferior"
using target_gdbarch suffices.
Note: We cannot call get_current_arch because it may try to access
the target, which may involve accessing data in the pspace currently
being deleted. */
struct gdbarch *arch = target_gdbarch ();
gdbpy_enter enter_py (arch);
gdbpy_ref<pspace_object> object ((pspace_object *) datum);
object->pspace = NULL;
}
/* Return a new reference to the Python object of type Pspace
representing PSPACE. If the object has already been created,
return it. Otherwise, create it. Return NULL and set the Python
@ -492,8 +494,7 @@ py_free_pspace (struct program_space *pspace, void *datum)
gdbpy_ref<>
pspace_to_pspace_object (struct program_space *pspace)
{
PyObject *result
((PyObject *) program_space_data (pspace, pspy_pspace_data_key));
PyObject *result = (PyObject *) pspy_pspace_data_key.get (pspace);
if (result == NULL)
{
gdbpy_ref<pspace_object> object
@ -504,7 +505,7 @@ pspace_to_pspace_object (struct program_space *pspace)
return NULL;
object->pspace = pspace;
set_program_space_data (pspace, pspy_pspace_data_key, object.get ());
pspy_pspace_data_key.set (pspace, object.get ());
result = (PyObject *) object.release ();
}
@ -528,14 +529,6 @@ gdbpy_is_progspace (PyObject *obj)
return PyObject_TypeCheck (obj, &pspace_object_type);
}
void _initialize_py_progspace ();
void
_initialize_py_progspace ()
{
pspy_pspace_data_key
= register_program_space_data_with_cleanup (NULL, py_free_pspace);
}
int
gdbpy_initialize_pspace (void)
{

View File

@ -50,7 +50,26 @@ struct symbol_object {
} \
} while (0)
static const struct objfile_data *sympy_objfile_data_key;
/* A deleter that is used when an objfile is about to be freed. */
struct symbol_object_deleter
{
void operator() (symbol_object *obj)
{
while (obj)
{
symbol_object *next = obj->next;
obj->symbol = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
};
static const registry<objfile>::key<symbol_object, symbol_object_deleter>
sympy_objfile_data_key;
static PyObject *
sympy_str (PyObject *self)
@ -307,11 +326,10 @@ set_symbol (symbol_object *obj, struct symbol *symbol)
{
struct objfile *objfile = symbol->objfile ();
obj->next = ((symbol_object *)
objfile_data (objfile, sympy_objfile_data_key));
obj->next = sympy_objfile_data_key.get (objfile);
if (obj->next)
obj->next->prev = obj;
set_objfile_data (objfile, sympy_objfile_data_key, obj);
sympy_objfile_data_key.set (objfile, obj);
}
else
obj->next = NULL;
@ -350,10 +368,7 @@ sympy_dealloc (PyObject *obj)
else if (sym_obj->symbol != NULL
&& sym_obj->symbol->is_objfile_owned ()
&& sym_obj->symbol->symtab () != NULL)
{
set_objfile_data (sym_obj->symbol->objfile (),
sympy_objfile_data_key, sym_obj->next);
}
sympy_objfile_data_key.set (sym_obj->symbol->objfile (), sym_obj->next);
if (sym_obj->next)
sym_obj->next->prev = sym_obj->prev;
sym_obj->symbol = NULL;
@ -596,38 +611,6 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
return return_list.release ();
}
/* This function is called when an objfile is about to be freed.
Invalidate the symbol as further actions on the symbol would result
in bad data. All access to obj->symbol should be gated by
SYMPY_REQUIRE_VALID which will raise an exception on invalid
symbols. */
static void
del_objfile_symbols (struct objfile *objfile, void *datum)
{
symbol_object *obj = (symbol_object *) datum;
while (obj)
{
symbol_object *next = obj->next;
obj->symbol = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
void _initialize_py_symbol ();
void
_initialize_py_symbol ()
{
/* Register an objfile "free" callback so we can properly
invalidate symbol when an object file that is about to be
deleted. */
sympy_objfile_data_key
= register_objfile_data_with_cleanup (NULL, del_objfile_symbols);
}
int
gdbpy_initialize_symbols (void)
{

View File

@ -37,9 +37,31 @@ struct symtab_object {
symtab_object *next;
};
/* This function is called when an objfile is about to be freed.
Invalidate the symbol table as further actions on the symbol table
would result in bad data. All access to obj->symtab should be
gated by STPY_REQUIRE_VALID which will raise an exception on
invalid symbol tables. */
struct stpy_deleter
{
void operator() (symtab_object *obj)
{
while (obj)
{
symtab_object *next = obj->next;
obj->symtab = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
};
extern PyTypeObject symtab_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("symtab_object");
static const struct objfile_data *stpy_objfile_data_key;
static const registry<objfile>::key<symtab_object, stpy_deleter>
stpy_objfile_data_key;
/* Require a valid symbol table. All access to symtab_object->symtab
should be gated by this call. */
@ -68,9 +90,39 @@ struct sal_object {
sal_object *next;
};
/* This is called when an objfile is about to be freed. Invalidate
the sal object as further actions on the sal would result in bad
data. All access to obj->sal should be gated by
SALPY_REQUIRE_VALID which will raise an exception on invalid symbol
table and line objects. */
struct salpy_deleter
{
void operator() (sal_object *obj)
{
gdbpy_enter enter_py;
while (obj)
{
sal_object *next = obj->next;
gdbpy_ref<> tmp (obj->symtab);
obj->symtab = Py_None;
Py_INCREF (Py_None);
obj->next = NULL;
obj->prev = NULL;
xfree (obj->sal);
obj->sal = NULL;
obj = next;
}
}
};
extern PyTypeObject sal_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("sal_object");
static const struct objfile_data *salpy_objfile_data_key;
static const registry<objfile>::key<sal_object, salpy_deleter>
salpy_objfile_data_key;
/* Require a valid symbol table and line object. All access to
sal_object->sal should be gated by this call. */
@ -246,10 +298,8 @@ stpy_dealloc (PyObject *obj)
if (symtab->prev)
symtab->prev->next = symtab->next;
else if (symtab->symtab)
{
set_objfile_data (symtab->symtab->compunit ()->objfile (),
stpy_objfile_data_key, symtab->next);
}
stpy_objfile_data_key.set (symtab->symtab->compunit ()->objfile (),
symtab->next);
if (symtab->next)
symtab->next->prev = symtab->prev;
symtab->symtab = NULL;
@ -329,9 +379,9 @@ salpy_dealloc (PyObject *self)
if (self_sal->prev)
self_sal->prev->next = self_sal->next;
else if (self_sal->symtab != Py_None)
set_objfile_data
salpy_objfile_data_key.set
(symtab_object_to_symtab (self_sal->symtab)->compunit ()->objfile (),
salpy_objfile_data_key, self_sal->next);
self_sal->next);
if (self_sal->next)
self_sal->next->prev = self_sal->prev;
@ -378,13 +428,11 @@ set_sal (sal_object *sal_obj, struct symtab_and_line sal)
symtab *symtab = symtab_object_to_symtab (sal_obj->symtab);
sal_obj->next
= ((sal_object *) objfile_data (symtab->compunit ()->objfile (),
salpy_objfile_data_key));
= salpy_objfile_data_key.get (symtab->compunit ()->objfile ());
if (sal_obj->next)
sal_obj->next->prev = sal_obj;
set_objfile_data (symtab->compunit ()->objfile (),
salpy_objfile_data_key, sal_obj);
salpy_objfile_data_key.set (symtab->compunit ()->objfile (), sal_obj);
}
else
sal_obj->next = NULL;
@ -404,14 +452,10 @@ set_symtab (symtab_object *obj, struct symtab *symtab)
obj->prev = NULL;
if (symtab)
{
obj->next
= ((symtab_object *)
objfile_data (symtab->compunit ()->objfile (),
stpy_objfile_data_key));
obj->next = stpy_objfile_data_key.get (symtab->compunit ()->objfile ());
if (obj->next)
obj->next->prev = obj;
set_objfile_data (symtab->compunit ()->objfile (),
stpy_objfile_data_key, obj);
stpy_objfile_data_key.set (symtab->compunit ()->objfile (), obj);
}
else
obj->next = NULL;
@ -465,68 +509,6 @@ symtab_object_to_symtab (PyObject *obj)
return ((symtab_object *) obj)->symtab;
}
/* This function is called when an objfile is about to be freed.
Invalidate the symbol table as further actions on the symbol table
would result in bad data. All access to obj->symtab should be
gated by STPY_REQUIRE_VALID which will raise an exception on
invalid symbol tables. */
static void
del_objfile_symtab (struct objfile *objfile, void *datum)
{
symtab_object *obj = (symtab_object *) datum;
while (obj)
{
symtab_object *next = obj->next;
obj->symtab = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
/* This function is called when an objfile is about to be freed.
Invalidate the sal object as further actions on the sal
would result in bad data. All access to obj->sal should be
gated by SALPY_REQUIRE_VALID which will raise an exception on
invalid symbol table and line objects. */
static void
del_objfile_sal (struct objfile *objfile, void *datum)
{
sal_object *obj = (sal_object *) datum;
while (obj)
{
sal_object *next = obj->next;
gdbpy_ref<> tmp (obj->symtab);
obj->symtab = Py_None;
Py_INCREF (Py_None);
obj->next = NULL;
obj->prev = NULL;
xfree (obj->sal);
obj->sal = NULL;
obj = next;
}
}
void _initialize_py_symtab ();
void
_initialize_py_symtab ()
{
/* Register an objfile "free" callback so we can properly
invalidate symbol tables, and symbol table and line data
structures when an object file that is about to be
deleted. */
stpy_objfile_data_key
= register_objfile_data_with_cleanup (NULL, del_objfile_symtab);
salpy_objfile_data_key
= register_objfile_data_with_cleanup (NULL, del_objfile_sal);
}
int
gdbpy_initialize_symtabs (void)
{

View File

@ -1109,36 +1109,38 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
static const struct objfile_data *typy_objfile_data_key;
static void
save_objfile_types (struct objfile *objfile, void *datum)
/* Deleter that saves types when an objfile is being destroyed. */
struct typy_deleter
{
type_object *obj = (type_object *) datum;
void operator() (type_object *obj)
{
if (!gdb_python_initialized)
return;
if (!gdb_python_initialized)
return;
/* This prevents another thread from freeing the objects we're
operating on. */
gdbpy_enter enter_py;
/* This prevents another thread from freeing the objects we're
operating on. */
gdbpy_enter enter_py (objfile->arch ());
htab_up copied_types = create_copied_types_hash ();
htab_up copied_types = create_copied_types_hash ();
while (obj)
{
type_object *next = obj->next;
while (obj)
{
type_object *next = obj->next;
htab_empty (copied_types.get ());
htab_empty (copied_types.get ());
obj->type = copy_type_recursive (obj->type, copied_types.get ());
obj->type = copy_type_recursive (obj->type, copied_types.get ());
obj->next = NULL;
obj->prev = NULL;
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
}
};
obj = next;
}
}
static const registry<objfile>::key<type_object, typy_deleter>
typy_objfile_data_key;
static void
set_type (type_object *obj, struct type *type)
@ -1149,11 +1151,10 @@ set_type (type_object *obj, struct type *type)
{
struct objfile *objfile = type->objfile_owner ();
obj->next = ((type_object *)
objfile_data (objfile, typy_objfile_data_key));
obj->next = typy_objfile_data_key.get (objfile);
if (obj->next)
obj->next->prev = obj;
set_objfile_data (objfile, typy_objfile_data_key, obj);
typy_objfile_data_key.set (objfile, obj);
}
else
obj->next = NULL;
@ -1172,7 +1173,7 @@ typy_dealloc (PyObject *obj)
struct objfile *objfile = type->type->objfile_owner ();
if (objfile)
set_objfile_data (objfile, typy_objfile_data_key, type->next);
typy_objfile_data_key.set (objfile, type->next);
}
if (type->next)
type->next->prev = type->prev;
@ -1464,14 +1465,6 @@ gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
return type_to_type_object (type);
}
void _initialize_py_type ();
void
_initialize_py_type ()
{
typy_objfile_data_key
= register_objfile_data_with_cleanup (save_objfile_types, NULL);
}
int
gdbpy_initialize_types (void)
{