[gnu.gdb.bug] GDB vs GNU C++

tiemann@SUN.COM (Michael Tiemann) (12/01/89)

These diffs fix a performance bug I wrote into GDB about two years
ago.  The bug is that when you ask GDB to print the value of `foo', it
has to look up `foo' in the various contexts that `foo' could belong
to.  In the case of member functions, it must check whether `foo' is a
field of `this'.  In the original code I wrote, I saved the wrong
cycles when I indirected `this' to get the structure definition so I
could look up the name in the type.  In parallel with doing the
indirection for the name lookup, I had GDB go and fetch the object
from memory, so its value would be close at hand on a hit.  Well, this
leads to slightly reduced performance in the case where the object is
small, it's just a call to ptrace that didn't need to be made.

However, I was wondering why GDB was taking so long to find that a
particular name was not in scope, and I found that my object, all 200K
of it, was being ptraced into my address space just to do the search!
Yow!  

    teacake% diff -c2 valops.c~ valops.c
    *** valops.c~	Sun Nov  5 10:04:33 1989
    --- valops.c	Thu Nov 30 21:36:54 1989
    ***************
    *** 1009,1017 ****

	while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
    !     {
    !       arg1 = value_ind (arg1);
    !       COERCE_ARRAY (arg1);
    !       t = VALUE_TYPE (arg1);
    !     }

	if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
    --- 1009,1013 ----

	while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
    !     t = TYPE_TARGET_TYPE (t);

	if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
    ***************
    *** 1030,1036 ****
	      char *t_field_name = TYPE_FIELD_NAME (t, i);
	      if (t_field_name && !strcmp (t_field_name, name))
    ! 	    {
    ! 	      return 1;
    ! 	    }
	    }
	    if (TYPE_N_BASECLASSES (t) == 0)
    --- 1026,1030 ----
	      char *t_field_name = TYPE_FIELD_NAME (t, i);
	      if (t_field_name && !strcmp (t_field_name, name))
    ! 	    goto success;
	    }
	    if (TYPE_N_BASECLASSES (t) == 0)
    ***************
    *** 1038,1042 ****

	    t = TYPE_BASECLASS (t, 1);
    -       VALUE_TYPE (arg1) = t;	/* side effect! */
	  }

    --- 1032,1035 ----
    ***************
    *** 1048,1052 ****
	/* Destructors are a special case.  */
	if (destructor_name_p (name, t))
    !     return 1;

	while (t)
    --- 1041,1045 ----
	/* Destructors are a special case.  */
	if (destructor_name_p (name, t))
    !     goto success;

	while (t)
    ***************
    *** 1064,1067 ****
    --- 1057,1069 ----
	  }
	return 0;
    + 
    +  success:
    +   t = VALUE_TYPE (arg1);
    +   while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
    +     {
    +       arg1 = value_ind (arg1);
    +       COERCE_ARRAY (arg1);
    +       t = VALUE_TYPE (arg1);
    +     }
      }

    teacake% 

This could still be done better: `check_field' should not read in the
whole object.  It should be up to the caller to decide whether to
ptrace in the memory.  Right now the following code from
`lookup_symbol' (symtab.c)

  /* C++: If requested to do so by the caller, 
     check to see if NAME is a field of `this'. */
  if (is_a_field_of_this)
    {
      int v = (int) value_of_this (0);
      
      *is_a_field_of_this = 0;
      if (v && check_field (v, name))
	{
	  *is_a_field_of_this = 1;	    
	  return 0;
	}
    }

is the only place where check_field is called, and it clearly is not
using its value.  Since the published interface of `check_field' does
not indicate that it brings values in from disk, I advocate removing
that paging-in mis-feature altogether, but I'll leave the final
decision to Jim.

Michael