[RFA,6/8] Use value_freer in dwarf2_evaluate_loc_desc_full

Message ID 1480395946-10924-7-git-send-email-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey Nov. 29, 2016, 5:05 a.m. UTC
  This changes dwarf2_evaluate_loc_desc_full to use value_freer.

Note that this function previously called do_cleanup using the same
cleanup multiple times.  I had thought this was buggy, but re-reading
make_my_cleanup2 indicates that it is not.  Nevertheless it is
surprising, and at least one of the calls (the one that is completely
removed in this patch) seems to have been done under the assumption
that it would still have some effect.

2016-11-28  Tom Tromey  <tom@tromey.com>

	* value.h (value_freer::~value_freer): Call release.
	(value_freer::release): New method.
	* dwarf2loc.c (dwarf2_evaluate_loc_desc_full): Use value_freer.
---
 gdb/ChangeLog   |  6 ++++++
 gdb/dwarf2loc.c | 27 +++++++++++++--------------
 gdb/value.h     | 12 +++++++++++-
 3 files changed, 30 insertions(+), 15 deletions(-)
  

Comments

Pedro Alves Dec. 2, 2016, 2:45 p.m. UTC | #1
On 11/29/2016 05:05 AM, Tom Tromey wrote:
> This changes dwarf2_evaluate_loc_desc_full to use value_freer.
> 
> Note that this function previously called do_cleanup using the same
> cleanup multiple times.  I had thought this was buggy, but re-reading
> make_my_cleanup2 indicates that it is not.  Nevertheless it is
> surprising, and at least one of the calls (the one that is completely
> removed in this patch) seems to have been done under the assumption
> that it would still have some effect.
> 
> 2016-11-28  Tom Tromey  <tom@tromey.com>
> 
> 	* value.h (value_freer::~value_freer): Call release.
> 	(value_freer::release): New method.
> 	* dwarf2loc.c (dwarf2_evaluate_loc_desc_full): Use value_freer.
> ---
>  gdb/ChangeLog   |  6 ++++++
>  gdb/dwarf2loc.c | 27 +++++++++++++--------------
>  gdb/value.h     | 12 +++++++++++-
>  3 files changed, 30 insertions(+), 15 deletions(-)
> 
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 6197bfb..cf61306 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,5 +1,11 @@
>  2016-11-28  Tom Tromey  <tom@tromey.com>
>  
> +	* value.h (value_freer::~value_freer): Call release.
> +	(value_freer::release): New method.
> +	* dwarf2loc.c (dwarf2_evaluate_loc_desc_full): Use value_freer.
> +
> +2016-11-28  Tom Tromey  <tom@tromey.com>
> +
>  	* python/py-value.c (valpy_dereference, valpy_referenced_value)
>  	(valpy_reference_value, valpy_const_value, valpy_get_address)
>  	(valpy_get_dynamic_type, valpy_lazy_string, valpy_do_cast)
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index 0d8a47c..43c95b8 100644
> --- a/gdb/dwarf2loc.c
> +++ b/gdb/dwarf2loc.c
> @@ -2321,7 +2321,6 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
>  			       LONGEST byte_offset)
>  {
>    struct value *retval;
> -  struct cleanup *value_chain;
>    struct objfile *objfile = dwarf2_per_cu_objfile (per_cu);
>  
>    if (byte_offset < 0)
> @@ -2335,7 +2334,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
>    ctx.per_cu = per_cu;
>    ctx.obj_address = 0;
>  
> -  value_chain = make_cleanup_value_free_to_mark (value_mark ());
> +  value_freer free_values;
>  
>    ctx.gdbarch = get_objfile_arch (objfile);
>    ctx.addr_size = dwarf2_per_cu_addr_size (per_cu);
> @@ -2350,7 +2349,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
>      {
>        if (ex.error == NOT_AVAILABLE_ERROR)
>  	{
> -	  do_cleanups (value_chain);
> +	  free_values.release ();

"release ()" looks potentially confusing to me, if you're in an
"unique_ptr" mindset, where release means the opposite -- to stop
managing.  Can we call that something else?

Maybe "free", since the class is called value_freer?

Or "reset ()", following the naming used in the standard smart pointers?

The latter could be naturally extended to support

  free_values.reset (value_mark ());

later too, if we need it.

Thanks,
Pedro Alves
  
Tom Tromey Dec. 13, 2016, 1:28 p.m. UTC | #2
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> Or "reset ()", following the naming used in the standard smart pointers?

I went with reset since I think "free" can be a macro sometimes.
Or at least it could in C... not actually sure if C++ removed this
possibility.

Tom
  
Pedro Alves Dec. 20, 2016, 2:49 p.m. UTC | #3
On 12/13/2016 01:28 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
> 
> Pedro> Or "reset ()", following the naming used in the standard smart pointers?
> 
> I went with reset since I think "free" can be a macro sometimes.
> Or at least it could in C... not actually sure if C++ removed this
> possibility.

I always assumed it has, but had never went looking for the specific
wording.  Looking at the C++14 draft N4140, I see:

 17.6.1.2 - Headers:

 5 - Names which are defined as macros in C shall be defined as macros in
 the C ++ standard library, even if C grants license for implementation 
 as functions. [ Note: The names defined as macros in C include the
 following: assert, offsetof, setjmp, va_arg, va_end, and va_start. - end note ]

 6 - Names that are defined as functions in C shall be defined as functions in
 the C ++ standard library." (175)

And then footnote 175 clarifies:

 "175) This disallows the practice, allowed in C, of providing a masking
 macro in addition to the function prototype. The only way to achieve equivalent
 inline behavior in C ++ is to provide a definition as an extern inline function."


So I think the answer is yes, C++ removes that possibility.


BTW, I meanwhile realized that "release" would also be a
naming/concept conflict with release_value / value_release_to_mark
too.  Really best to avoid it here.

In pondering a bit more over this, I wonder whether
adding a "scoped_" to go with scoped_restore etc., would make
it a bit clearer to readers that this is a RAII type.  Then
also considering value_release_to_mark, I wonder would an
API/naming like this:

struct scoped_value_mark
{
   scoped_value_mark () : m_value (value_mark ()) {}
   ~scoped_value_mark () { free_to_mark ()}

   void free_to_mark () { if (m_value) value_free_to_mark (m_value); }
   void release_to_mark () { if (m_value) value_release_to_mark (m_value); }

   /* Get the mark value.  */
   struct value *get () { return m_value; }
};

Uses would look like:

 scoped_value_mark value_mark;
 ...
    value_mark.free_to_mark (); // some path than wants an explicit "free_to_mark".


In eval.c:fetch_subexp_value we'd use it like:

  /* Evaluate the expression.  */
  scoped_value_mark mark;

  [...]
      result = evaluate_subexp (NULL_TYPE, exp, pc, EVAL_NORMAL);
  [...]

  new_mark = value_mark ();
  if (mark.get () == new_mark)
    return;

  /* Make sure it's not lazy, so that after the target stops again we
     have a non-lazy previous value to compare with.  */
  [...]

  if (val_chain)
    {
      /* Return the chain of intermediate values.  We use this to
	 decide which addresses to watch.  */
      *val_chain = new_mark;
      mark.release_to_mark ();
    }
}

Would this result in clearer client code?  IMHO, yes, but WDYT?

Thanks,
Pedro Alves
  
Tom Tromey Dec. 23, 2016, 7:05 p.m. UTC | #4
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> In pondering a bit more over this, I wonder whether
Pedro> adding a "scoped_" to go with scoped_restore etc., would make
Pedro> it a bit clearer to readers that this is a RAII type.  Then
Pedro> also considering value_release_to_mark, I wonder would an
Pedro> API/naming like this:
[...]
Pedro> Would this result in clearer client code?  IMHO, yes, but WDYT?

It looks good to me.  I've made this change and I'll send the new
patches soon.

FYI I've only implemented the subset of the proposed API that was needed
by the patches I have.

Tom
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 6197bfb..cf61306 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@ 
 2016-11-28  Tom Tromey  <tom@tromey.com>
 
+	* value.h (value_freer::~value_freer): Call release.
+	(value_freer::release): New method.
+	* dwarf2loc.c (dwarf2_evaluate_loc_desc_full): Use value_freer.
+
+2016-11-28  Tom Tromey  <tom@tromey.com>
+
 	* python/py-value.c (valpy_dereference, valpy_referenced_value)
 	(valpy_reference_value, valpy_const_value, valpy_get_address)
 	(valpy_get_dynamic_type, valpy_lazy_string, valpy_do_cast)
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 0d8a47c..43c95b8 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -2321,7 +2321,6 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 			       LONGEST byte_offset)
 {
   struct value *retval;
-  struct cleanup *value_chain;
   struct objfile *objfile = dwarf2_per_cu_objfile (per_cu);
 
   if (byte_offset < 0)
@@ -2335,7 +2334,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
   ctx.per_cu = per_cu;
   ctx.obj_address = 0;
 
-  value_chain = make_cleanup_value_free_to_mark (value_mark ());
+  value_freer free_values;
 
   ctx.gdbarch = get_objfile_arch (objfile);
   ctx.addr_size = dwarf2_per_cu_addr_size (per_cu);
@@ -2350,7 +2349,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
     {
       if (ex.error == NOT_AVAILABLE_ERROR)
 	{
-	  do_cleanups (value_chain);
+	  free_values.release ();
 	  retval = allocate_value (type);
 	  mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
 	  return retval;
@@ -2359,7 +2358,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 	{
 	  if (entry_values_debug)
 	    exception_print (gdb_stdout, ex);
-	  do_cleanups (value_chain);
+	  free_values.release ();
 	  return allocate_optimized_out_value (type);
 	}
       else
@@ -2382,7 +2381,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 				  ctx.addr_size, frame);
       /* We must clean up the value chain after creating the piece
 	 closure but before allocating the result.  */
-      do_cleanups (value_chain);
+      free_values.release ();
       retval = allocate_computed_value (type, &pieced_value_funcs, c);
       set_value_offset (retval, byte_offset);
     }
@@ -2399,7 +2398,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 
 	    if (byte_offset != 0)
 	      error (_("cannot use offset on synthetic pointer to register"));
-	    do_cleanups (value_chain);
+	    free_values.release ();
 	    retval = value_from_register (type, gdb_regnum, frame);
 	    if (value_optimized_out (retval))
 	      {
@@ -2411,7 +2410,6 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 		   inspecting a register ($pc, $sp, etc.), return a
 		   generic optimized out value instead, so that we show
 		   <optimized out> instead of <not saved>.  */
-		do_cleanups (value_chain);
 		tmp = allocate_value (type);
 		value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type));
 		retval = tmp;
@@ -2445,7 +2443,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 	      }
 	    address = value_as_address (value_from_pointer (ptr_type, address));
 
-	    do_cleanups (value_chain);
+	    free_values.release ();
 	    retval = value_at_lazy (type, address + byte_offset);
 	    if (in_stack_memory)
 	      set_value_stack (retval, 1);
@@ -2458,6 +2456,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 	    gdb_byte *contents;
 	    const gdb_byte *val_bytes;
 	    size_t n = TYPE_LENGTH (value_type (value));
+	    struct cleanup *cleanup;
 
 	    if (byte_offset + TYPE_LENGTH (type) > n)
 	      invalid_synthetic_pointer ();
@@ -2470,8 +2469,8 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 	       to the mark, but we still need the value contents
 	       below.  */
 	    value_incref (value);
-	    do_cleanups (value_chain);
-	    make_cleanup_value_free (value);
+	    free_values.release ();
+	    cleanup = make_cleanup_value_free (value);
 
 	    retval = allocate_value (type);
 	    contents = value_contents_raw (retval);
@@ -2484,6 +2483,8 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 		n = TYPE_LENGTH (type);
 	      }
 	    memcpy (contents, val_bytes, n);
+
+	    do_cleanups (cleanup);
 	  }
 	  break;
 
@@ -2496,7 +2497,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 	    if (byte_offset + TYPE_LENGTH (type) > n)
 	      invalid_synthetic_pointer ();
 
-	    do_cleanups (value_chain);
+	    free_values.release ();
 	    retval = allocate_value (type);
 	    contents = value_contents_raw (retval);
 
@@ -2516,7 +2517,7 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 	  break;
 
 	case DWARF_VALUE_OPTIMIZED_OUT:
-	  do_cleanups (value_chain);
+	  free_values.release ();
 	  retval = allocate_optimized_out_value (type);
 	  break;
 
@@ -2532,8 +2533,6 @@  dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 
   set_value_initialized (retval, ctx.initialized);
 
-  do_cleanups (value_chain);
-
   return retval;
 }
 
diff --git a/gdb/value.h b/gdb/value.h
index 399bf48..43dfe14 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -728,7 +728,17 @@  class value_freer
 
   ~value_freer ()
   {
-    value_free_to_mark (m_value);
+    release ();
+  }
+
+  /* Free the values currently on the value stack.  */
+  void release ()
+  {
+    if (m_value != NULL)
+      {
+	value_free_to_mark (m_value);
+	m_value = NULL;
+      }
   }
 
  private: