This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr)


From: Simon Marchi <simon.marchi@polymtl.ca>

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.
---
 gdb/extension-priv.h         |  75 ++------------------
 gdb/extension.c              | 158 ++++++-------------------------------------
 gdb/extension.h              | 108 ++++++++++++++++++++---------
 gdb/python/py-xmethods.c     | 154 ++++++++++++++++++-----------------------
 gdb/python/python-internal.h |  21 +-----
 gdb/python/python.c          |   5 --
 gdb/valops.c                 |  52 ++++++--------
 gdb/value.c                  |  30 ++++----
 gdb/value.h                  |   7 +-
 9 files changed, 208 insertions(+), 402 deletions(-)

diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h
index 4d16ac5..6f02904 100644
--- a/gdb/extension-priv.h
+++ b/gdb/extension-priv.h
@@ -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.  */
diff --git a/gdb/extension.c b/gdb/extension.c
index 4ffad03..969f2b2 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.  */
-
-/* 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)
-{
-  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.  */
+/* See extension.h.  */
 
-VEC (xmethod_worker_ptr) *
-get_matching_xmethod_workers (struct type *type, const char *method_name)
+void
+get_matching_xmethod_workers (struct type *type, const char *method_name,
+			      std::vector<xmethod_worker_up> *workers)
 {
-  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;
-
-  gdb_assert (extlang->ops->get_xmethod_arg_types != NULL);
+  type **type_array = 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;
-
-  gdb_assert (extlang->ops->get_xmethod_arg_types != NULL);
+  type *result_type;
 
-  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 2c79411..e1f26ac 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
 {
-  /* The language the xmethod worker is implemented in.  */
-  const struct extension_language_defn *extlang;
+  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.  */
 
-  /* The extension language specific data for this xmethod worker.  */
-  void *data;
+  type *get_result_type (value *object, value **args, int nargs);
 
-  /* The TYPE_CODE_XMETHOD value corresponding to this worker.
-     Always use value_of_xmethod to access it.  */
-  struct value *value;
+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 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);
-
-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 *);
+/* 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 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 */
diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c
index e061da2..6d839c5 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 ();
 
-static struct xmethod_worker *new_python_xmethod_worker (PyObject *item,
-							 PyObject *py_obj_type);
+  DISABLE_COPY_AND_ASSIGN (python_xmethod_worker);
 
-/* Implementation of free_xmethod_worker_data for Python.  */
+  /* Implementation of xmethod_worker::invoke for Python.  */
 
-void
-gdbpy_free_xmethod_worker_data (const struct extension_language_defn *extlang,
-				void *data)
-{
-  struct gdbpy_worker_data *worker_data = (struct gdbpy_worker_data *) data;
+  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.
 
-  gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
+     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;
+};
+
+python_xmethod_worker::~python_xmethod_worker ()
+{
   /* 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 (py_worker != NULL && this_type != NULL);
+  gdb_assert (m_py_worker != NULL && m_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 8fc8cc5..5a93fe1 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<xmethod_worker_up> *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 9ed9b6b..b0bdfcd 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 ccc2bc2..f9f9439 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<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
 	{
diff --git a/gdb/value.c b/gdb/value.c
index 3e0ca25..992cfcb 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 e0de844..b9c063b 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);
-- 
2.7.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]