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:
Simon Marchi 2018-01-07 09:25:32 -05:00 committed by Simon Marchi
parent d672364615
commit ba18742c3a
10 changed files with 294 additions and 404 deletions

View File

@ -1,3 +1,87 @@
2018-01-07 Simon Marchi <simon.marchi@polymtl.ca>
* 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.
2018-01-05 Pedro Alves <palves@redhat.com>
PR gdb/18653

View File

@ -25,26 +25,6 @@
#include <signal.h>
#include "cli/cli-script.h"
/* The return code for some API calls. */
enum ext_lang_rc
{
/* The operation completed successfully. */
EXT_LANG_RC_OK,
/* The operation was not performed (e.g., no pretty-printer). */
EXT_LANG_RC_NOP,
/* There was an error (e.g., Python error while printing a value).
When an error occurs no further extension languages are tried.
This is to preserve existing behaviour, and because it's convenient
for Python developers.
Note: This is different than encountering a memory error trying to read
a value for pretty-printing. Here we're referring to, e.g., programming
errors that trigger an exception in the extension language. */
EXT_LANG_RC_ERROR
};
/* High level description of an extension/scripting language.
An entry for each is compiled into GDB regardless of whether the support
is present. This is done so that we can issue meaningful errors if the
@ -261,63 +241,18 @@ struct extension_language_ops
enum ext_lang_rc (*before_prompt) (const struct extension_language_defn *,
const char *current_gdb_prompt);
/* xmethod support:
clone_xmethod_worker_data, free_xmethod_worker_data,
get_matching_xmethod_workers, get_xmethod_arg_types,
get_xmethod_return_type, invoke_xmethod.
These methods are optional and may be NULL, but if one of them is
implemented then they all must be. */
/* Clone DATA and return a new but identical xmethod worker data
object for this extension language. */
void * (*clone_xmethod_worker_data)
(const struct extension_language_defn *extlang, void *data);
/* Free the DATA object of this extension language. */
void (*free_xmethod_worker_data)
(const struct extension_language_defn *extlang, void *data);
/* Return a vector of matching xmethod workers defined in this
extension language. The workers service methods with name
METHOD_NAME on objects of type OBJ_TYPE. The vector is returned
in DM_VEC. */
in DM_VEC.
This field may be NULL if the extension language does not support
xmethods. */
enum ext_lang_rc (*get_matching_xmethod_workers)
(const struct extension_language_defn *extlang,
struct type *obj_type,
const char *method_name,
xmethod_worker_vec **dm_vec);
/* Given a WORKER servicing a particular method, return the types
of the arguments the method takes. The number of arguments is
returned in NARGS, and their types are returned in the array
ARGTYPES. */
enum ext_lang_rc (*get_xmethod_arg_types)
(const struct extension_language_defn *extlang,
struct xmethod_worker *worker,
int *nargs,
struct type ***arg_types);
/* Given a WORKER servicing a particular method, fetch the type of the
result of the method. OBJECT, ARGS, NARGS are the same as for
invoke_xmethod. The result type is stored in *RESULT_TYPE.
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. */
enum ext_lang_rc (*get_xmethod_result_type)
(const struct extension_language_defn *extlang,
struct xmethod_worker *worker,
struct value *object, struct value **args, int nargs,
struct type **result_type);
/* Invoke the xmethod serviced by WORKER. The xmethod is invoked
on OBJECT with arguments in the array ARGS. NARGS is the length of
this array. Returns the value returned by the xmethod. */
struct value * (*invoke_xmethod)
(const struct extension_language_defn *extlang,
struct xmethod_worker *worker,
struct value *object,
struct value **args,
int nargs);
std::vector<xmethod_worker_up> *dm_vec);
};
/* State necessary to restore a signal handler to its previous value. */

View File

@ -850,68 +850,18 @@ check_quit_flag (void)
return result;
}
/* xmethod support. */
/* The xmethod API routines do not have "ext_lang" in the name because
the name "xmethod" implies that this routine deals with extension
languages. Plus some of the methods take a xmethod_foo * "self/this"
arg, not an extension_language_defn * arg. */
/* See extension.h. */
/* Returns a new xmethod_worker with EXTLANG and DATA. Space for the
result must be freed with free_xmethod_worker. */
struct xmethod_worker *
new_xmethod_worker (const struct extension_language_defn *extlang, void *data)
void
get_matching_xmethod_workers (struct type *type, const char *method_name,
std::vector<xmethod_worker_up> *workers)
{
struct xmethod_worker *worker = XCNEW (struct xmethod_worker);
worker->extlang = extlang;
worker->data = data;
worker->value = NULL;
return worker;
}
/* Clones WORKER and returns a new but identical worker.
The function get_matching_xmethod_workers (see below), returns a
vector of matching workers. If a particular worker is selected by GDB
to invoke a method, then this function can help in cloning the
selected worker and freeing up the vector via a cleanup.
Space for the result must be freed with free_xmethod_worker. */
struct xmethod_worker *
clone_xmethod_worker (struct xmethod_worker *worker)
{
struct xmethod_worker *new_worker;
const struct extension_language_defn *extlang = worker->extlang;
gdb_assert (extlang->ops->clone_xmethod_worker_data != NULL);
new_worker = new_xmethod_worker
(extlang,
extlang->ops->clone_xmethod_worker_data (extlang, worker->data));
return new_worker;
}
/* If a method with name METHOD_NAME is to be invoked on an object of type
TYPE, then all entension languages are searched for implementations of
methods with name METHOD. All matches found are returned as a vector
of 'xmethod_worker_ptr' objects. If no matching methods are
found, NULL is returned. */
VEC (xmethod_worker_ptr) *
get_matching_xmethod_workers (struct type *type, const char *method_name)
{
VEC (xmethod_worker_ptr) *workers = NULL;
int i;
const struct extension_language_defn *extlang;
ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
{
VEC (xmethod_worker_ptr) *lang_workers, *new_vec;
enum ext_lang_rc rc;
/* If an extension language does not support xmethods, ignore
@ -921,115 +871,45 @@ get_matching_xmethod_workers (struct type *type, const char *method_name)
rc = extlang->ops->get_matching_xmethod_workers (extlang,
type, method_name,
&lang_workers);
workers);
if (rc == EXT_LANG_RC_ERROR)
{
free_xmethod_worker_vec (workers);
error (_("Error while looking for matching xmethod workers "
"defined in %s."), extlang->capitalized_name);
}
new_vec = VEC_merge (xmethod_worker_ptr, workers, lang_workers);
/* Free only the vectors and not the elements as NEW_VEC still
contains them. */
VEC_free (xmethod_worker_ptr, workers);
VEC_free (xmethod_worker_ptr, lang_workers);
workers = new_vec;
error (_("Error while looking for matching xmethod workers "
"defined in %s."), extlang->capitalized_name);
}
return workers;
}
/* Return the arg types of the xmethod encapsulated in WORKER.
An array of arg types is returned. The length of the array is returned in
NARGS. The type of the 'this' object is returned as the first element of
array. */
/* See extension.h. */
struct type **
get_xmethod_arg_types (struct xmethod_worker *worker, int *nargs)
type **
xmethod_worker::get_arg_types (int *nargs)
{
enum ext_lang_rc rc;
struct type **type_array = NULL;
const struct extension_language_defn *extlang = worker->extlang;
type **type_array = NULL;
gdb_assert (extlang->ops->get_xmethod_arg_types != NULL);
rc = extlang->ops->get_xmethod_arg_types (extlang, worker, nargs,
&type_array);
ext_lang_rc rc = do_get_arg_types (nargs, &type_array);
if (rc == EXT_LANG_RC_ERROR)
{
error (_("Error while looking for arg types of a xmethod worker "
"defined in %s."), extlang->capitalized_name);
}
error (_("Error while looking for arg types of a xmethod worker "
"defined in %s."), m_extlang->capitalized_name);
return type_array;
}
/* Return the type of the result of the xmethod encapsulated in WORKER.
OBJECT, ARGS, NARGS are the same as for invoke_xmethod. */
/* See extension.h. */
struct type *
get_xmethod_result_type (struct xmethod_worker *worker,
struct value *object, struct value **args, int nargs)
xmethod_worker::get_result_type (value *object, value **args, int nargs)
{
enum ext_lang_rc rc;
struct type *result_type;
const struct extension_language_defn *extlang = worker->extlang;
type *result_type;
gdb_assert (extlang->ops->get_xmethod_arg_types != NULL);
rc = extlang->ops->get_xmethod_result_type (extlang, worker,
object, args, nargs,
&result_type);
ext_lang_rc rc = do_get_result_type (object, args, nargs, &result_type);
if (rc == EXT_LANG_RC_ERROR)
{
error (_("Error while fetching result type of an xmethod worker "
"defined in %s."), extlang->capitalized_name);
"defined in %s."), m_extlang->capitalized_name);
}
return result_type;
}
/* Invokes the xmethod encapsulated in WORKER and returns the result.
The method is invoked on OBJ with arguments in the ARGS array. NARGS is
the length of the this array. */
struct value *
invoke_xmethod (struct xmethod_worker *worker, struct value *obj,
struct value **args, int nargs)
{
gdb_assert (worker->extlang->ops->invoke_xmethod != NULL);
return worker->extlang->ops->invoke_xmethod (worker->extlang, worker,
obj, args, nargs);
}
/* Frees the xmethod worker WORKER. */
void
free_xmethod_worker (struct xmethod_worker *worker)
{
gdb_assert (worker->extlang->ops->free_xmethod_worker_data != NULL);
worker->extlang->ops->free_xmethod_worker_data (worker->extlang,
worker->data);
xfree (worker);
}
/* Frees a vector of xmethod_workers VEC. */
void
free_xmethod_worker_vec (void *vec)
{
int i;
struct xmethod_worker *worker;
VEC (xmethod_worker_ptr) *v = (VEC (xmethod_worker_ptr) *) vec;
for (i = 0; VEC_iterate (xmethod_worker_ptr, v, i, worker); i++)
free_xmethod_worker (worker);
VEC_free (xmethod_worker_ptr, v);
}
/* Called via an observer before gdb prints its prompt.
Iterate over the extension languages giving them a chance to
change the prompt. The first one to change the prompt wins,

View File

@ -146,26 +146,85 @@ struct ext_lang_type_printers
void *py_type_printers;
};
/* The return code for some API calls. */
enum ext_lang_rc
{
/* The operation completed successfully. */
EXT_LANG_RC_OK,
/* The operation was not performed (e.g., no pretty-printer). */
EXT_LANG_RC_NOP,
/* There was an error (e.g., Python error while printing a value).
When an error occurs no further extension languages are tried.
This is to preserve existing behaviour, and because it's convenient
for Python developers.
Note: This is different than encountering a memory error trying to read
a value for pretty-printing. Here we're referring to, e.g., programming
errors that trigger an exception in the extension language. */
EXT_LANG_RC_ERROR
};
/* A type which holds its extension language specific xmethod worker data. */
struct xmethod_worker
{
xmethod_worker (const extension_language_defn *extlang)
: m_extlang (extlang)
{}
virtual ~xmethod_worker () = default;
/* Invoke the xmethod encapsulated in this worker and return the result.
The method is invoked on OBJ with arguments in the ARGS array. NARGS is
the length of the this array. */
virtual value *invoke (value *obj, value **args, int nargs) = 0;
/* Clone this worker, returns a new but identical worker.
The function get_matching_xmethod_workers returns a vector of matching
workers. If a particular worker is selected by GDB to invoke a method,
then this function can help in cloning the selected worker. */
virtual std::unique_ptr<xmethod_worker> clone () = 0;
/* Return the arg types of the xmethod encapsulated in this worker.
An array of arg types is returned. The length of the array is returned in
NARGS. The type of the 'this' object is returned as the first element of
array. */
type **get_arg_types (int *nargs);
/* Return the type of the result of the xmethod encapsulated in this worker.
OBJECT, ARGS, NARGS are the same as for invoke. */
type *get_result_type (value *object, value **args, int nargs);
private:
/* Return the types of the arguments the method takes. The number of
arguments is returned in NARGS, and their types are returned in the array
ARGTYPES. */
virtual enum ext_lang_rc do_get_arg_types
(int *nargs, struct type ***arg_types) = 0;
/* Fetch the type of the result of the method implemented by this worker.
OBJECT, ARGS, NARGS are the same as for the invoked method. The result
type is stored in *RESULT_TYPE. */
virtual enum ext_lang_rc do_get_result_type
(struct value *obj, struct value **args, int nargs,
struct type **result_type_ptr) = 0;
/* The language the xmethod worker is implemented in. */
const struct extension_language_defn *extlang;
/* The extension language specific data for this xmethod worker. */
void *data;
/* The TYPE_CODE_XMETHOD value corresponding to this worker.
Always use value_of_xmethod to access it. */
struct value *value;
const extension_language_defn *m_extlang;
};
typedef struct xmethod_worker *xmethod_worker_ptr;
DEF_VEC_P (xmethod_worker_ptr);
typedef VEC (xmethod_worker_ptr) xmethod_worker_vec;
typedef std::unique_ptr<xmethod_worker> xmethod_worker_up;
/* The interface for gdb's own extension(/scripting) language. */
extern const struct extension_language_defn extension_language_gdb;
@ -242,26 +301,13 @@ extern const struct extension_language_defn *get_breakpoint_cond_ext_lang
extern int breakpoint_ext_lang_cond_says_stop (struct breakpoint *);
extern struct value *invoke_xmethod (struct xmethod_worker *,
struct value *,
struct value **, int nargs);
/* If a method with name METHOD_NAME is to be invoked on an object of type
TYPE, then all extension languages are searched for implementations of
methods with name METHOD_NAME. All matches found are appended to the WORKERS
vector. */
extern struct xmethod_worker *clone_xmethod_worker (struct xmethod_worker *);
extern struct xmethod_worker *new_xmethod_worker
(const struct extension_language_defn *extlang, void *data);
extern void free_xmethod_worker (struct xmethod_worker *);
extern void free_xmethod_worker_vec (void *vec);
extern xmethod_worker_vec *get_matching_xmethod_workers
(struct type *, const char *);
extern struct type **get_xmethod_arg_types (struct xmethod_worker *, int *);
extern struct type *get_xmethod_result_type (struct xmethod_worker *,
struct value *object,
struct value **args, int nargs);
extern void get_matching_xmethod_workers
(struct type *type, const char *method_name,
std::vector<xmethod_worker_up> *workers);
#endif /* EXTENSION_H */

View File

@ -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

View File

@ -463,28 +463,11 @@ extern enum ext_lang_bp_stop gdbpy_breakpoint_cond_says_stop
extern int gdbpy_breakpoint_has_cond (const struct extension_language_defn *,
struct breakpoint *b);
extern void *gdbpy_clone_xmethod_worker_data
(const struct extension_language_defn *extlang, void *data);
extern void gdbpy_free_xmethod_worker_data
(const struct extension_language_defn *extlang, void *data);
extern 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);
extern 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);
extern enum ext_lang_rc gdbpy_get_xmethod_result_type
(const struct extension_language_defn *extlang,
struct xmethod_worker *worker,
struct value *object, struct value **args, int nargs,
struct type **result_type);
extern struct value *gdbpy_invoke_xmethod
(const struct extension_language_defn *extlang,
struct xmethod_worker *worker,
struct value *obj, struct value **args, int nargs);
std::vector<xmethod_worker_up> *dm_vec);
PyObject *gdbpy_history (PyObject *self, PyObject *args);
PyObject *gdbpy_breakpoints (PyObject *, PyObject *);

View File

@ -190,12 +190,7 @@ const struct extension_language_ops python_extension_ops =
gdbpy_before_prompt_hook,
gdbpy_clone_xmethod_worker_data,
gdbpy_free_xmethod_worker_data,
gdbpy_get_matching_xmethod_workers,
gdbpy_get_xmethod_arg_types,
gdbpy_get_xmethod_result_type,
gdbpy_invoke_xmethod
};
/* Architecture and language to be used in callbacks from

View File

@ -68,7 +68,8 @@ int find_oload_champ_namespace_loop (struct value **, int,
const int no_adl);
static int find_oload_champ (struct value **, int, int,
struct fn_field *, VEC (xmethod_worker_ptr) *,
struct fn_field *,
const std::vector<xmethod_worker_up> *,
struct symbol **, struct badness_vector **);
static int oload_method_static_p (struct fn_field *, int);
@ -98,7 +99,7 @@ static struct value *cast_into_complex (struct type *, struct value *);
static void find_method_list (struct value **, const char *,
LONGEST, struct type *, struct fn_field **, int *,
VEC (xmethod_worker_ptr) **,
std::vector<xmethod_worker_up> *,
struct type **, LONGEST *);
#if 0
@ -2282,12 +2283,11 @@ static void
find_method_list (struct value **argp, const char *method,
LONGEST offset, struct type *type,
struct fn_field **fn_list, int *num_fns,
VEC (xmethod_worker_ptr) **xm_worker_vec,
std::vector<xmethod_worker_up> *xm_worker_vec,
struct type **basetype, LONGEST *boffset)
{
int i;
struct fn_field *f = NULL;
VEC (xmethod_worker_ptr) *worker_vec = NULL, *new_vec = NULL;
gdb_assert (fn_list != NULL && xm_worker_vec != NULL);
type = check_typedef (type);
@ -2328,12 +2328,7 @@ find_method_list (struct value **argp, const char *method,
and hence there is no point restricting them with something like method
hiding. Moreover, if hiding is done for xmethods as well, then we will
have to provide a mechanism to un-hide (like the 'using' construct). */
worker_vec = get_matching_xmethod_workers (type, method);
new_vec = VEC_merge (xmethod_worker_ptr, *xm_worker_vec, worker_vec);
VEC_free (xmethod_worker_ptr, *xm_worker_vec);
VEC_free (xmethod_worker_ptr, worker_vec);
*xm_worker_vec = new_vec;
get_matching_xmethod_workers (type, method, xm_worker_vec);
/* If source methods are not found in current class, look for them in the
base classes. We also have to go through the base classes to gather
@ -2382,7 +2377,7 @@ static void
value_find_oload_method_list (struct value **argp, const char *method,
LONGEST offset, struct fn_field **fn_list,
int *num_fns,
VEC (xmethod_worker_ptr) **xm_worker_vec,
std::vector<xmethod_worker_up> *xm_worker_vec,
struct type **basetype, LONGEST *boffset)
{
struct type *t;
@ -2409,7 +2404,7 @@ value_find_oload_method_list (struct value **argp, const char *method,
/* Clear the lists. */
*fn_list = NULL;
*num_fns = 0;
*xm_worker_vec = NULL;
xm_worker_vec->clear ();
find_method_list (argp, method, 0, t, fn_list, num_fns, xm_worker_vec,
basetype, boffset);
@ -2488,8 +2483,8 @@ find_overload_match (struct value **args, int nargs,
struct fn_field *fns_ptr = NULL;
/* For non-methods, the list of overloaded function symbols. */
struct symbol **oload_syms = NULL;
/* For xmethods, the VEC of xmethod workers. */
VEC (xmethod_worker_ptr) *xm_worker_vec = NULL;
/* For xmethods, the vector of xmethod workers. */
std::vector<xmethod_worker_up> xm_worker_vec;
/* Number of overloaded instances being considered. */
int num_fns = 0;
struct type *basetype = NULL;
@ -2534,8 +2529,8 @@ find_overload_match (struct value **args, int nargs,
value_find_oload_method_list (&temp, name, 0, &fns_ptr, &num_fns,
&xm_worker_vec, &basetype, &boffset);
/* If this is a method only search, and no methods were found
the search has faild. */
if (method == METHOD && (!fns_ptr || !num_fns) && !xm_worker_vec)
the search has failed. */
if (method == METHOD && (!fns_ptr || !num_fns) && xm_worker_vec.empty ())
error (_("Couldn't find method %s%s%s"),
obj_type_name,
(obj_type_name && *obj_type_name) ? "::" : "",
@ -2558,15 +2553,14 @@ find_overload_match (struct value **args, int nargs,
make_cleanup (xfree, src_method_badness);
}
if (VEC_length (xmethod_worker_ptr, xm_worker_vec) > 0)
if (!xm_worker_vec.empty ())
{
ext_method_oload_champ = find_oload_champ (args, nargs,
0, NULL, xm_worker_vec,
0, NULL, &xm_worker_vec,
NULL, &ext_method_badness);
ext_method_match_quality = classify_oload_match (ext_method_badness,
nargs, 0);
make_cleanup (xfree, ext_method_badness);
make_cleanup (free_xmethod_worker_vec, xm_worker_vec);
}
if (src_method_oload_champ >= 0 && ext_method_oload_champ >= 0)
@ -2783,11 +2777,8 @@ find_overload_match (struct value **args, int nargs,
basetype, boffset);
}
else
{
*valp = value_of_xmethod (clone_xmethod_worker
(VEC_index (xmethod_worker_ptr, xm_worker_vec,
ext_method_oload_champ)));
}
*valp = value_from_xmethod
(xm_worker_vec[ext_method_oload_champ]->clone ());
}
else
*symp = oload_syms[func_oload_champ];
@ -2992,12 +2983,11 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
static int
find_oload_champ (struct value **args, int nargs,
int num_fns, struct fn_field *fns_ptr,
VEC (xmethod_worker_ptr) *xm_worker_vec,
const std::vector<xmethod_worker_up> *xm_worker_vec,
struct symbol **oload_syms,
struct badness_vector **oload_champ_bv)
{
int ix;
int fn_count;
/* A measure of how good an overloaded instance is. */
struct badness_vector *bv;
/* Index of best overloaded function. */
@ -3014,9 +3004,8 @@ find_oload_champ (struct value **args, int nargs,
*oload_champ_bv = NULL;
fn_count = (xm_worker_vec != NULL
? VEC_length (xmethod_worker_ptr, xm_worker_vec)
: num_fns);
int fn_count = xm_worker_vec != NULL ? xm_worker_vec->size () : num_fns;
/* Consider each candidate in turn. */
for (ix = 0; ix < fn_count; ix++)
{
@ -3024,12 +3013,11 @@ find_oload_champ (struct value **args, int nargs,
int static_offset = 0;
int nparms;
struct type **parm_types;
struct xmethod_worker *worker = NULL;
if (xm_worker_vec != NULL)
{
worker = VEC_index (xmethod_worker_ptr, xm_worker_vec, ix);
parm_types = get_xmethod_arg_types (worker, &nparms);
xmethod_worker *worker = (*xm_worker_vec)[ix].get ();
parm_types = worker->get_arg_types (&nparms);
}
else
{

View File

@ -1627,7 +1627,7 @@ value_free (struct value *val)
funcs->free_closure (val);
}
else if (VALUE_LVAL (val) == lval_xcallable)
free_xmethod_worker (val->location.xm_worker);
delete val->location.xm_worker;
xfree (val->contents);
VEC_free (range_s, val->unavailable);
@ -2697,23 +2697,20 @@ show_convenience (const char *ignore, int from_tty)
}
}
/* Return the TYPE_CODE_XMETHOD value corresponding to WORKER. */
/* See value.h. */
struct value *
value_of_xmethod (struct xmethod_worker *worker)
value_from_xmethod (xmethod_worker_up &&worker)
{
if (worker->value == NULL)
{
struct value *v;
struct value *v;
v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
v->lval = lval_xcallable;
v->location.xm_worker = worker;
v->modifiable = 0;
worker->value = v;
}
v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
v->lval = lval_xcallable;
v->location.xm_worker = worker.release ();
v->modifiable = 0;
return worker->value;
return v;
}
/* Return the type of the result of TYPE_CODE_XMETHOD value METHOD. */
@ -2724,8 +2721,8 @@ result_type_of_xmethod (struct value *method, int argc, struct value **argv)
gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
&& method->lval == lval_xcallable && argc > 0);
return get_xmethod_result_type (method->location.xm_worker,
argv[0], argv + 1, argc - 1);
return method->location.xm_worker->get_result_type
(argv[0], argv + 1, argc - 1);
}
/* Call the xmethod corresponding to the TYPE_CODE_XMETHOD value METHOD. */
@ -2736,8 +2733,7 @@ call_xmethod (struct value *method, int argc, struct value **argv)
gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
&& method->lval == lval_xcallable && argc > 0);
return invoke_xmethod (method->location.xm_worker,
argv[0], argv + 1, argc - 1);
return method->location.xm_worker->invoke (argv[0], argv + 1, argc - 1);
}
/* Extract a value as a C number (either long or double).

View File

@ -21,6 +21,7 @@
#define VALUE_H 1
#include "frame.h" /* For struct frame_id. */
#include "extension.h"
struct block;
struct expression;
@ -30,7 +31,6 @@ struct type;
struct ui_file;
struct language_defn;
struct value_print_options;
struct xmethod_worker;
/* Values can be partially 'optimized out' and/or 'unavailable'.
These are distinct states and have different string representations
@ -1158,7 +1158,10 @@ struct value *call_internal_function (struct gdbarch *gdbarch,
char *value_internal_function_name (struct value *);
extern struct value *value_of_xmethod (struct xmethod_worker *);
/* Build a value wrapping and representing WORKER. The value takes ownership
of the xmethod_worker object. */
extern struct value *value_from_xmethod (xmethod_worker_up &&worker);
extern struct type *result_type_of_xmethod (struct value *method,
int argc, struct value **argv);