public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 2/2] Remove xmethod_worker::clone
  2017-11-27 13:54 [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr) Simon Marchi
@ 2017-11-27 13:54 ` Simon Marchi
  2018-01-07 14:27 ` [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr) Simon Marchi
  1 sibling, 0 replies; 4+ messages in thread
From: Simon Marchi @ 2017-11-27 13:54 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

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

I think that the clone method of xmethod_worker can be removed.  It is
only used in find_overload_match, to clone an xmethod we want to
keep.  Instead, we can just std::move it out of the vector and into
value_from_xmethod.  value_from_xmethod creates a value that will own
the xmethod_worker from that point.  Other xmethod_workers left in the
vector will get destroyed when the vector gets destroyed, but the chosen
one will keep living inside the value struct.

gdb/ChangeLog:

	* extension.h (struct xmethod_worker) <clone>: Remove.
	* python/py-xmethods.c (struct python_xmethod_worker) <clone>:
	Remove.
	(python_xmethod_worker::clone): Remove.
	* valops.c (find_overload_match): Use std::move instead of
	clone.
---
 gdb/extension.h          |  7 -------
 gdb/python/py-xmethods.c | 17 -----------------
 gdb/valops.c             |  2 +-
 3 files changed, 1 insertion(+), 25 deletions(-)

diff --git a/gdb/extension.h b/gdb/extension.h
index e1f26ac..ebdcb34 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -182,13 +182,6 @@ struct xmethod_worker
 
   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
diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c
index 6d839c5..31d0bda 100644
--- a/gdb/python/py-xmethods.c
+++ b/gdb/python/py-xmethods.c
@@ -48,10 +48,6 @@ struct python_xmethod_worker : xmethod_worker
 
   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;
@@ -80,19 +76,6 @@ python_xmethod_worker::~python_xmethod_worker ()
   Py_DECREF (m_this_type);
 }
 
-/* See declaration.  */
-
-xmethod_worker_up
-python_xmethod_worker::clone ()
-{
-  /* We don't do much here, but we still need the GIL.  */
-  gdbpy_enter enter_py (get_current_arch (), current_language);
-
-  xmethod_worker *worker = new python_xmethod_worker (m_py_worker, m_this_type);
-
-  return xmethod_worker_up (worker);
-}
-
 /* Invoke the "match" method of the MATCHER and return a new reference
    to the result.  Returns NULL on error.  */
 
diff --git a/gdb/valops.c b/gdb/valops.c
index f9f9439..32dc083 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -2778,7 +2778,7 @@ find_overload_match (struct value **args, int nargs,
 	}
       else
 	*valp = value_from_xmethod
-	  (xm_worker_vec[ext_method_oload_champ]->clone ());
+	  (std::move (xm_worker_vec[ext_method_oload_champ]));
     }
   else
     *symp = oload_syms[func_oload_champ];
-- 
2.7.4

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr)
@ 2017-11-27 13:54 Simon Marchi
  2017-11-27 13:54 ` [PATCH 2/2] Remove xmethod_worker::clone Simon Marchi
  2018-01-07 14:27 ` [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr) Simon Marchi
  0 siblings, 2 replies; 4+ messages in thread
From: Simon Marchi @ 2017-11-27 13:54 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

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;
 }
-\f
-/* 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);
-}
-\f
 /* 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;
 
-\f
 /* 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);
+
 \f
 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)
     }
 }
 \f
-/* 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);
 }
 \f
 /* 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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr)
  2017-11-27 13:54 [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr) Simon Marchi
  2017-11-27 13:54 ` [PATCH 2/2] Remove xmethod_worker::clone Simon Marchi
@ 2018-01-07 14:27 ` Simon Marchi
  1 sibling, 0 replies; 4+ messages in thread
From: Simon Marchi @ 2018-01-07 14:27 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

On 2017-11-27 08:53, Simon Marchi wrote:
> 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.

I pushed these two patches in.

Simon

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr)
@ 2017-11-27  0:48 Simon Marchi
  0 siblings, 0 replies; 4+ messages in thread
From: Simon Marchi @ 2017-11-27  0:48 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

The initial goal of this patch was to remove the usage of
VEC(xmethod_worker_ptr).  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 4d16ac5062..6f02904e8d 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 4ffad038c9..969f2b2620 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -850,68 +850,18 @@ check_quit_flag (void)
 
   return result;
 }
-\f
-/* 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);
-}
-\f
 /* 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 2c79411e4f..e1f26acdc1 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;
 
-\f
 /* 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 e061da2192..6d839c5dac 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 8fc8cc5a5d..5a93fe193d 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);
+
 \f
 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 9ed9b6b1ca..b0bdfcd049 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 ccc2bc2afe..f9f9439b0c 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 3e0ca25fa7..992cfcb3f5 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)
     }
 }
 \f
-/* 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);
 }
 \f
 /* Extract a value as a C number (either long or double).
diff --git a/gdb/value.h b/gdb/value.h
index e0de84427e..b9c063bda2 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.15.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-01-07 14:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-27 13:54 [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr) Simon Marchi
2017-11-27 13:54 ` [PATCH 2/2] Remove xmethod_worker::clone Simon Marchi
2018-01-07 14:27 ` [PATCH 1/2] C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr) Simon Marchi
  -- strict thread matches above, loose matches on Subject: below --
2017-11-27  0:48 Simon Marchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).