From ba18742c3a1b62ff218db99bee47bb932af6dab9 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Sun, 7 Jan 2018 09:25:32 -0500 Subject: [PATCH] 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) : Remove. : Remove. : Chance VEC to std::vector. : Remove. : Remove. : 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. : Remove. : Remove. : New virtual pure methods. : 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. : 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. --- gdb/ChangeLog | 84 +++++++++++++++++++ gdb/extension-priv.h | 75 ++--------------- gdb/extension.c | 158 +++++------------------------------ gdb/extension.h | 108 +++++++++++++++++------- gdb/python/py-xmethods.c | 158 +++++++++++++++-------------------- gdb/python/python-internal.h | 21 +---- gdb/python/python.c | 5 -- gdb/valops.c | 52 +++++------- gdb/value.c | 30 +++---- gdb/value.h | 7 +- 10 files changed, 294 insertions(+), 404 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 24ccfe68824..65b9ef9a864 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,87 @@ +2018-01-07 Simon Marchi + + * extension-priv.h (enum ext_lang_rc): Remove, move to extension.h. + (struct extension_language_ops) : Remove. + : Remove. + : Chance VEC to std::vector. + : Remove. + : Remove. + : 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. + : Remove. + : Remove. + : New + virtual pure methods. + : 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. + : 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 PR gdb/18653 diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index 8fbf1b0c769..5843479f93c 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -25,26 +25,6 @@ #include #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 *dm_vec); }; /* State necessary to restore a signal handler to its previous value. */ diff --git a/gdb/extension.c b/gdb/extension.c index a1ee3510a6f..224b05c7ed0 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -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 *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, diff --git a/gdb/extension.h b/gdb/extension.h index 04f90490ebb..475d712b420 100644 --- a/gdb/extension.h +++ b/gdb/extension.h @@ -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 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_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 *workers); #endif /* EXTENSION_H */ diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c index 750f2635796..f4064c29dcf 100644 --- a/gdb/python/py-xmethods.c +++ b/gdb/python/py-xmethods.c @@ -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 *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 diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index f32a2582093..f38f0b30cb8 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -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 *dm_vec); + PyObject *gdbpy_history (PyObject *self, PyObject *args); PyObject *gdbpy_breakpoints (PyObject *, PyObject *); diff --git a/gdb/python/python.c b/gdb/python/python.c index 4844c86c543..9eae8a1aef2 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -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 diff --git a/gdb/valops.c b/gdb/valops.c index 9525dc8499e..8fccfe93019 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -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 *, 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 *, 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 *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 *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 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 *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 { diff --git a/gdb/value.c b/gdb/value.c index d4b4673f66e..9a144fb7fb6 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -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). diff --git a/gdb/value.h b/gdb/value.h index 7dc67dc7216..e0ea22d4e52 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -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);