C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr)
The initial goal of this patch was to remove the usage of VEC(xmethod_worker_ptr) and corresponding cleanups. I ended up having to C++ify the xmethod_worker code, to be able to have xmethod_workers free their data in destructors, and therefore be able to use vectors of xmethod_worker unique_ptr. The operations in extension_language_ops that act on one instance of xmethod_worker (get result type, get args type, invoke) are transformed to methods of xmethod_worker. xmethod_worker becomes an abstract base class with virtual pure methods which python_xmethod_worker implements. The only xmethod-related operation left in extension_language_ops is get_matching_xmethod_workers, which returns a list of xmethod_workers. The changes are relatively straightforward, but here are some notes on things that may raise eyebrows: - I was not really comfortable with the value_of_xmethod function. At first it looks like a simple getter, so I considered making it a method of xmethod_worker. But actually it creates a value and transfers the ownership of the xmethod_worker to it. It would be a bit weird and error-prone if calling a method on an object silently removed the ownership of the object from the caller. To reflect the behavior more accurately, I renamed it to value_from_xmethod and made it accept an rvalue-reference (so the caller knows it gives away the ownership). I noticed the backlink from xmethod_worker to its owning value was not used, so I removed it. - Some code, like get_matching_xmethod_workers, made each callee fill a new vector, which was then merged in the result vector. I think it's safe if we always pass the same vector around, and each implementation just appends to it. - The clone operation does not seem particularly useful, it is removed in the following patch. gdb/ChangeLog: * extension-priv.h (enum ext_lang_rc): Remove, move to extension.h. (struct extension_language_ops) <clone_xmethod_worker_data>: Remove. <free_xmethod_worker_data>: Remove. <get_matching_xmethod_workers>: Chance VEC to std::vector. <get_xmethod_arg_types>: Remove. <get_xmethod_result_type>: Remove. <invoke_xmethod>: Remove. * extension.c (new_xmethod_worker): Remove. (clone_xmethod_worker): Remove. (get_matching_xmethod_workers): Return void, pass std::vector by pointer. (get_xmethod_arg_types): Rename to... (xmethod_worker::get_arg_types): ... this, and adjust. (get_xmethod_result_type): Rename to... (xmethod_worker::get_result_type): ... this, and adjust. (invoke_xmethod): Remove. (free_xmethod_worker): Remove. (free_xmethod_worker_vec): Remove. * extension.h (enum ext_lang_rc): Move here from extension-priv.h. (struct xmethod_worker): Add constructor and destructor. <data>: Remove. <value>: Remove. <invoke, clone, do_get_result_type, do_get_arg_types>: New virtual pure methods. <get_arg_types, get_result_type>: New methods. (xmethod_worker_ptr): Remove typedef. (DEF_VEC_P (xmethod_worker_ptr)): Remove. (xmethod_worker_vec): Remove typedef. (xmethod_worker_up): New typedef. (invoke_xmethod): Remove. (clone_xmethod_worker): Remove. (free_xmethod_worker): Remove. (free_xmethod_worker_vec): Remove. (get_xmethod_arg_types): Remove. (get_xmethod_result_type): Remove. * valops.c (find_method_list): Use std::vector, don't use intermediate vector. (value_find_oload_method_list): Use std::vector. (find_overload_match): Use std::vector. (find_oload_champ): Use std::vector. * value.c (value_free): Use operator delete. (value_of_xmethod): Rename to... (value_from_xmethod): ... this. Don't assign xmethod_worker::value, take rvalue-reference. (result_type_of_xmethod): Adjust. (call_xmethod): Adjust. * value.h: Include extension.h. (struct xmethod_worker): Don't forward-declare. (value_of_xmethod): Rename to... (value_from_xmethod): ... this, take rvalue-reference. * python/py-xmethods.c (struct gdbpy_worker_data): Rename to... (struct python_xmethod_worker): ... this, add constructor and destructor. <invoke, clone, do_get_arg_types, do_get_result_type>: Implement. (gdbpy_free_xmethod_worker_data): Rename to... (python_xmethod_worker::~python_xmethod_worker): ... this and adjust. (gdbpy_clone_xmethod_worker_data): Rename to... (python_xmethod_worker::clone): ... this and adjust. (gdbpy_get_matching_xmethod_workers): Use std::vector, don't use temporary vector. (gdbpy_get_xmethod_arg_types): Rename to... (python_xmethod_worker::do_get_arg_types): ... this and adjust. (gdbpy_get_xmethod_result_type): Rename to... (python_xmethod_worker::do_get_result_type): ... this and adjust. (gdbpy_invoke_xmethod): Rename to... (python_xmethod_worker::invoke): ... this and adjust. (new_python_xmethod_worker): Rename to... (python_xmethod_worker::python_xmethod_worker): ... this and adjust. * python/python-internal.h (gdbpy_clone_xmethod_worker_data): Remove. (gdbpy_free_xmethod_worker_data): Remove. (gdbpy_get_matching_xmethod_workers): Use std::vector. (gdbpy_get_xmethod_arg_types): Remove. (gdbpy_get_xmethod_result_type): Remove. (gdbpy_invoke_xmethod): Remove. * python/python.c (python_extension_ops): Remove obsolete callbacks.
This commit is contained in:
parent
d672364615
commit
ba18742c3a
10 changed files with 294 additions and 404 deletions
|
@ -37,54 +37,60 @@ static const char matchers_attr_str[] = "xmethods";
|
|||
static PyObject *py_match_method_name = NULL;
|
||||
static PyObject *py_get_arg_types_method_name = NULL;
|
||||
|
||||
struct gdbpy_worker_data
|
||||
struct python_xmethod_worker : xmethod_worker
|
||||
{
|
||||
PyObject *worker;
|
||||
PyObject *this_type;
|
||||
python_xmethod_worker (PyObject *worker, PyObject *this_type);
|
||||
~python_xmethod_worker ();
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (python_xmethod_worker);
|
||||
|
||||
/* Implementation of xmethod_worker::invoke for Python. */
|
||||
|
||||
value *invoke (value *obj, value **args, int nargs) override;
|
||||
|
||||
/* Implementation of xmethod_worker::clone for Python. */
|
||||
|
||||
xmethod_worker_up clone () override;
|
||||
|
||||
/* Implementation of xmethod_worker::do_get_arg_types for Python. */
|
||||
|
||||
ext_lang_rc do_get_arg_types (int *nargs, type ***arg_types) override;
|
||||
|
||||
/* Implementation of xmethod_worker::do_get_result_type for Python.
|
||||
|
||||
For backward compatibility with 7.9, which did not support getting the
|
||||
result type, if the get_result_type operation is not provided by WORKER
|
||||
then EXT_LANG_RC_OK is returned and NULL is returned in *RESULT_TYPE. */
|
||||
|
||||
ext_lang_rc do_get_result_type (value *obj, value **args, int nargs,
|
||||
type **result_type_ptr) override;
|
||||
|
||||
private:
|
||||
|
||||
PyObject *m_py_worker;
|
||||
PyObject *m_this_type;
|
||||
};
|
||||
|
||||
static struct xmethod_worker *new_python_xmethod_worker (PyObject *item,
|
||||
PyObject *py_obj_type);
|
||||
|
||||
/* Implementation of free_xmethod_worker_data for Python. */
|
||||
|
||||
void
|
||||
gdbpy_free_xmethod_worker_data (const struct extension_language_defn *extlang,
|
||||
void *data)
|
||||
python_xmethod_worker::~python_xmethod_worker ()
|
||||
{
|
||||
struct gdbpy_worker_data *worker_data = (struct gdbpy_worker_data *) data;
|
||||
|
||||
gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
|
||||
|
||||
/* We don't do much here, but we still need the GIL. */
|
||||
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||
|
||||
Py_DECREF (worker_data->worker);
|
||||
Py_DECREF (worker_data->this_type);
|
||||
xfree (worker_data);
|
||||
Py_DECREF (m_py_worker);
|
||||
Py_DECREF (m_this_type);
|
||||
}
|
||||
|
||||
/* Implementation of clone_xmethod_worker_data for Python. */
|
||||
/* See declaration. */
|
||||
|
||||
void *
|
||||
gdbpy_clone_xmethod_worker_data (const struct extension_language_defn *extlang,
|
||||
void *data)
|
||||
xmethod_worker_up
|
||||
python_xmethod_worker::clone ()
|
||||
{
|
||||
struct gdbpy_worker_data *worker_data
|
||||
= (struct gdbpy_worker_data *) data, *new_data;
|
||||
|
||||
gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
|
||||
|
||||
/* We don't do much here, but we still need the GIL. */
|
||||
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||
|
||||
new_data = XCNEW (struct gdbpy_worker_data);
|
||||
new_data->worker = worker_data->worker;
|
||||
new_data->this_type = worker_data->this_type;
|
||||
Py_INCREF (new_data->worker);
|
||||
Py_INCREF (new_data->this_type);
|
||||
xmethod_worker *worker = new python_xmethod_worker (m_py_worker, m_this_type);
|
||||
|
||||
return new_data;
|
||||
return xmethod_worker_up (worker);
|
||||
}
|
||||
|
||||
/* Invoke the "match" method of the MATCHER and return a new reference
|
||||
|
@ -130,10 +136,9 @@ enum ext_lang_rc
|
|||
gdbpy_get_matching_xmethod_workers
|
||||
(const struct extension_language_defn *extlang,
|
||||
struct type *obj_type, const char *method_name,
|
||||
xmethod_worker_vec **dm_vec)
|
||||
std::vector<xmethod_worker_up> *dm_vec)
|
||||
{
|
||||
struct objfile *objfile;
|
||||
VEC (xmethod_worker_ptr) *worker_vec = NULL;
|
||||
PyObject *py_progspace;
|
||||
|
||||
gdb_assert (obj_type != NULL && method_name != NULL);
|
||||
|
@ -282,39 +287,33 @@ gdbpy_get_matching_xmethod_workers
|
|||
break;
|
||||
}
|
||||
|
||||
worker = new_python_xmethod_worker (py_worker.get (),
|
||||
worker = new python_xmethod_worker (py_worker.get (),
|
||||
py_type.get ());
|
||||
VEC_safe_push (xmethod_worker_ptr, worker_vec, worker);
|
||||
|
||||
dm_vec->emplace_back (worker);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct xmethod_worker *worker;
|
||||
|
||||
worker = new_python_xmethod_worker (match_result.get (),
|
||||
worker = new python_xmethod_worker (match_result.get (),
|
||||
py_type.get ());
|
||||
VEC_safe_push (xmethod_worker_ptr, worker_vec, worker);
|
||||
dm_vec->emplace_back (worker);
|
||||
}
|
||||
}
|
||||
|
||||
*dm_vec = worker_vec;
|
||||
|
||||
return EXT_LANG_RC_OK;
|
||||
}
|
||||
|
||||
/* Implementation of get_xmethod_arg_types for Python. */
|
||||
/* See declaration. */
|
||||
|
||||
enum ext_lang_rc
|
||||
gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
|
||||
struct xmethod_worker *worker,
|
||||
int *nargs, struct type ***arg_types)
|
||||
ext_lang_rc
|
||||
python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
|
||||
{
|
||||
/* The gdbpy_enter object needs to be placed first, so that it's the last to
|
||||
be destroyed. */
|
||||
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||
struct gdbpy_worker_data *worker_data
|
||||
= (struct gdbpy_worker_data *) worker->data;
|
||||
PyObject *py_worker = worker_data->worker;
|
||||
struct type *obj_type;
|
||||
int i = 1, arg_count;
|
||||
gdbpy_ref<> list_iter;
|
||||
|
@ -324,7 +323,7 @@ gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
|
|||
*nargs = -1;
|
||||
|
||||
gdbpy_ref<> get_arg_types_method
|
||||
(PyObject_GetAttrString (py_worker, get_arg_types_method_name));
|
||||
(PyObject_GetAttrString (m_py_worker, get_arg_types_method_name));
|
||||
if (get_arg_types_method == NULL)
|
||||
{
|
||||
gdbpy_print_stack ();
|
||||
|
@ -332,7 +331,7 @@ gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
|
|||
}
|
||||
|
||||
gdbpy_ref<> py_argtype_list
|
||||
(PyObject_CallMethodObjArgs (py_worker, py_get_arg_types_method_name,
|
||||
(PyObject_CallMethodObjArgs (m_py_worker, py_get_arg_types_method_name,
|
||||
NULL));
|
||||
if (py_argtype_list == NULL)
|
||||
{
|
||||
|
@ -418,7 +417,7 @@ gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
|
|||
/* Add the type of 'this' as the first argument. The 'this' pointer should
|
||||
be a 'const' value. Hence, create a 'const' variant of the 'this' pointer
|
||||
type. */
|
||||
obj_type = type_object_to_type (worker_data->this_type);
|
||||
obj_type = type_object_to_type (m_this_type);
|
||||
(type_array.get ())[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
|
||||
NULL);
|
||||
*nargs = i;
|
||||
|
@ -427,18 +426,12 @@ gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
|
|||
return EXT_LANG_RC_OK;
|
||||
}
|
||||
|
||||
/* Implementation of get_xmethod_result_type for Python. */
|
||||
/* See declaration. */
|
||||
|
||||
enum ext_lang_rc
|
||||
gdbpy_get_xmethod_result_type (const struct extension_language_defn *extlang,
|
||||
struct xmethod_worker *worker,
|
||||
struct value *obj,
|
||||
struct value **args, int nargs,
|
||||
struct type **result_type_ptr)
|
||||
ext_lang_rc
|
||||
python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
|
||||
type **result_type_ptr)
|
||||
{
|
||||
struct gdbpy_worker_data *worker_data
|
||||
= (struct gdbpy_worker_data *) worker->data;
|
||||
PyObject *py_worker = worker_data->worker;
|
||||
struct type *obj_type, *this_type;
|
||||
int i;
|
||||
|
||||
|
@ -447,7 +440,7 @@ gdbpy_get_xmethod_result_type (const struct extension_language_defn *extlang,
|
|||
/* First see if there is a get_result_type method.
|
||||
If not this could be an old xmethod (pre 7.9.1). */
|
||||
gdbpy_ref<> get_result_type_method
|
||||
(PyObject_GetAttrString (py_worker, get_result_type_method_name));
|
||||
(PyObject_GetAttrString (m_py_worker, get_result_type_method_name));
|
||||
if (get_result_type_method == NULL)
|
||||
{
|
||||
PyErr_Clear ();
|
||||
|
@ -456,7 +449,7 @@ gdbpy_get_xmethod_result_type (const struct extension_language_defn *extlang,
|
|||
}
|
||||
|
||||
obj_type = check_typedef (value_type (obj));
|
||||
this_type = check_typedef (type_object_to_type (worker_data->this_type));
|
||||
this_type = check_typedef (type_object_to_type (m_this_type));
|
||||
if (TYPE_CODE (obj_type) == TYPE_CODE_PTR)
|
||||
{
|
||||
struct type *this_ptr = lookup_pointer_type (this_type);
|
||||
|
@ -528,24 +521,20 @@ gdbpy_get_xmethod_result_type (const struct extension_language_defn *extlang,
|
|||
return EXT_LANG_RC_OK;
|
||||
}
|
||||
|
||||
/* Implementation of invoke_xmethod for Python. */
|
||||
/* See declaration. */
|
||||
|
||||
struct value *
|
||||
gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
|
||||
struct xmethod_worker *worker,
|
||||
struct value *obj, struct value **args, int nargs)
|
||||
python_xmethod_worker::invoke (struct value *obj, struct value **args,
|
||||
int nargs)
|
||||
{
|
||||
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||
|
||||
int i;
|
||||
struct type *obj_type, *this_type;
|
||||
struct value *res = NULL;
|
||||
struct gdbpy_worker_data *worker_data
|
||||
= (struct gdbpy_worker_data *) worker->data;
|
||||
PyObject *xmethod_worker = worker_data->worker;
|
||||
|
||||
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||
|
||||
obj_type = check_typedef (value_type (obj));
|
||||
this_type = check_typedef (type_object_to_type (worker_data->this_type));
|
||||
this_type = check_typedef (type_object_to_type (m_this_type));
|
||||
if (TYPE_CODE (obj_type) == TYPE_CODE_PTR)
|
||||
{
|
||||
struct type *this_ptr = lookup_pointer_type (this_type);
|
||||
|
@ -597,7 +586,7 @@ gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
|
|||
PyTuple_SET_ITEM (py_arg_tuple.get (), i + 1, py_value_arg);
|
||||
}
|
||||
|
||||
gdbpy_ref<> py_result (PyObject_CallObject (xmethod_worker,
|
||||
gdbpy_ref<> py_result (PyObject_CallObject (m_py_worker,
|
||||
py_arg_tuple.get ()));
|
||||
if (py_result == NULL)
|
||||
{
|
||||
|
@ -623,24 +612,15 @@ gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
|
|||
return res;
|
||||
}
|
||||
|
||||
/* Creates a new Python xmethod_worker object.
|
||||
The new object has data of type 'struct gdbpy_worker_data' composed
|
||||
with the components PY_WORKER and THIS_TYPE. */
|
||||
|
||||
static struct xmethod_worker *
|
||||
new_python_xmethod_worker (PyObject *py_worker, PyObject *this_type)
|
||||
python_xmethod_worker::python_xmethod_worker (PyObject *py_worker,
|
||||
PyObject *this_type)
|
||||
: xmethod_worker (&extension_language_python),
|
||||
m_py_worker (py_worker), m_this_type (this_type)
|
||||
{
|
||||
struct gdbpy_worker_data *data;
|
||||
gdb_assert (m_py_worker != NULL && m_this_type != NULL);
|
||||
|
||||
gdb_assert (py_worker != NULL && this_type != NULL);
|
||||
|
||||
data = XCNEW (struct gdbpy_worker_data);
|
||||
data->worker = py_worker;
|
||||
data->this_type = this_type;
|
||||
Py_INCREF (py_worker);
|
||||
Py_INCREF (this_type);
|
||||
|
||||
return new_xmethod_worker (&extension_language_python, data);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue