Re: [RFA] "lazily" allocate the raw content of lazy values

Jerome Guitton
2008-11-25T11:27:33Z

[-- Attachment #1: Type: text/plain, Size: 1785 bytes --]

Tom Tromey (tromey@redhat.com):

> Jerome> Here, an elegant solution would be to manipulate lazy values instead
> Jerome> of references
> [...]
>
> Very nice background explanation, thanks.

You are welcome ;)

Thank you for your comments. I have taken them into account, with a few
additional changes:
* rename allocate_value_content to allocate_value_contents, for consistancy;
* remove the test "value->contents == NULL" in value_contents_raw and
value_contents_all_raw, as this is done in allocate_value_contents.

The new version of the patch is in attachment, re-tested against the
testsuite. Promoting this message to RFA now. OK to apply?

Thanks,
Jerome

2008-11-25 Jerome Guitton <guitton@adacore.com>

* value.h (allocate_value_lazy): New function declaration.
(value_free): Remove macro, make it a function.
* value.c (value): Move actual content outside of the memory space
of the struct; add a pointer to this actual content.
(allocate_value_lazy, allocate_value_contents): New function.
(allocate_value): Reimplement using these two new functions.
(value_contents_raw, value_contents_all_raw): If no memory
has been allocated yet for the actual content, allocate it.
(value_contents_all): Resync with struct value's changes.
(value_free): New function.
(value_copy, value_primitive_field): Use new function
allocate_value_lazy to allocate lazy values.
(value_change_enclosing_type): Resync with struct value's changes.
As the value is not reallocated, remove the special handling for
the value chain (now obsolete).
* valops.c (value_at_lazy): Use new function allocate_value_lazy.
(value_fetch_lazy): Allocate value content. Use allocate_value_lazy
to allocate lazy values.
(value_slice): Use allocate_value_lazy to allocate lazy values.

[-- Attachment #2: lazy_values.diff --]
[-- Type: text/x-diff, Size: 11242 bytes --]

Index: value.c
===================================================================
--- value.c (revision 139003)
+++ value.c (working copy)
@@ -163,21 +163,9 @@ struct value
/* If value is a variable, is it initialized or not. */
int initialized;

- /* Actual contents of the value. For use of this value; setting it
- uses the stuff above. Not valid if lazy is nonzero. Target
- byte-order. We force it to be aligned properly for any possible
- value. Note that a value therefore extends beyond what is
- declared here. */
- union
- {
- gdb_byte contents[1];
- DOUBLEST force_doublest_align;
- LONGEST force_longest_align;
- CORE_ADDR force_core_addr_align;
- void *force_pointer_align;
- } aligner;
- /* Do not add any new members here -- contents above will trash
- them. */
+ /* Actual contents of the value. Target byte-order. NULL or not valid if
+ lazy is nonzero. */
+ gdb_byte *contents;
};

/* Prototypes for local functions. */
@@ -213,15 +201,18 @@ static int value_history_count; /* Abs n

static struct value *all_values;

-/* Allocate a value that has the correct length for type TYPE. */
+/* Allocate a lazy value for type TYPE. Its actual content is
+ "lazily" allocated too: the content field of the return value is
+ NULL; it will be allocated when it is fetched from the target. */

struct value *
-allocate_value (struct type *type)
+allocate_value_lazy (struct type *type)
{
struct value *val;
struct type *atype = check_typedef (type);

- val = (struct value *) xzalloc (sizeof (struct value) + TYPE_LENGTH (atype));
+ val = (struct value *) xzalloc (sizeof (struct value));
+ val->contents = NULL;
val->next = all_values;
all_values = val;
val->type = type;
@@ -233,7 +224,7 @@ allocate_value (struct type *type)
val->bitpos = 0;
val->bitsize = 0;
VALUE_REGNUM (val) = -1;
- val->lazy = 0;
+ val->lazy = 1;
val->optimized_out = 0;
val->embedded_offset = 0;
val->pointed_to_offset = 0;
@@ -242,6 +233,28 @@ allocate_value (struct type *type)
return val;
}

+/* Allocate the contents of the value VAL if it has not been allocated yet. */
+
+void
+allocate_value_contents (struct value *val)
+{
+ if (!val->contents)
+ {
+ val->contents = (gdb_byte *) xzalloc (TYPE_LENGTH (val->enclosing_type));
+ }
+}
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+struct value *
+allocate_value (struct type *type)
+{
+ struct value *val = allocate_value_lazy (type);
+ allocate_value_contents (val);
+ val->lazy = 0;
+ return val;
+}
+
/* Allocate a value that has the correct length
for COUNT repetitions of type TYPE. */

@@ -340,13 +353,15 @@ set_value_bitsize (struct value *value,
gdb_byte *
value_contents_raw (struct value *value)
{
- return value->aligner.contents + value->embedded_offset;
+ allocate_value_contents (value);
+ return value->contents + value->embedded_offset;
}

gdb_byte *
value_contents_all_raw (struct value *value)
{
- return value->aligner.contents;
+ allocate_value_contents (value);
+ return value->contents;
}

struct type *
@@ -360,7 +375,7 @@ value_contents_all (struct value *value)
{
if (value->lazy)
value_fetch_lazy (value);
- return value->aligner.contents;
+ return value->contents;
}

int
@@ -495,6 +510,14 @@ value_mark (void)
return all_values;
}

+void
+value_free (struct value *val)
+{
+ if (val)
+ xfree (val->contents);
+ xfree (val);
+}
+
/* Free all values allocated since MARK was obtained by value_mark
(except for those released). */
void
@@ -579,7 +602,12 @@ struct value *
value_copy (struct value *arg)
{
struct type *encl_type = value_enclosing_type (arg);
- struct value *val = allocate_value (encl_type);
+ struct value *val;
+
+ if (value_lazy (arg))
+ val = allocate_value_lazy (encl_type);
+ else
+ val = allocate_value (encl_type);
val->type = arg->type;
VALUE_LVAL (val) = VALUE_LVAL (arg);
val->location = arg->location;
@@ -1319,39 +1347,12 @@ value_static_field (struct type *type, i
struct value *
value_change_enclosing_type (struct value *val, struct type *new_encl_type)
{
- if (TYPE_LENGTH (new_encl_type) <= TYPE_LENGTH (value_enclosing_type (val)))
- {
- val->enclosing_type = new_encl_type;
- return val;
- }
- else
- {
- struct value *new_val;
- struct value *prev;
-
- new_val = (struct value *) xrealloc (val, sizeof (struct value) + TYPE_LENGTH (new_encl_type));
-
- new_val->enclosing_type = new_encl_type;
-
- /* We have to make sure this ends up in the same place in the value
- chain as the original copy, so it's clean-up behavior is the same.
- If the value has been released, this is a waste of time, but there
- is no way to tell that in advance, so... */
-
- if (val != all_values)
- {
- for (prev = all_values; prev != NULL; prev = prev->next)
- {
- if (prev->next == val)
- {
- prev->next = new_val;
- break;
- }
- }
- }
-
- return new_val;
- }
+ if (TYPE_LENGTH (new_encl_type) > TYPE_LENGTH (value_enclosing_type (val)))
+ val->contents =
+ (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type));
+
+ val->enclosing_type = new_encl_type;
+ return val;
}

/* Given a value ARG1 (offset by OFFSET bytes)
@@ -1388,18 +1389,20 @@ value_primitive_field (struct value *arg
/* This field is actually a base subobject, so preserve the
entire object's contents for later references to virtual
bases, etc. */
- v = allocate_value (value_enclosing_type (arg1));
- v->type = type;

/* Lazy register values with offsets are not supported. */
if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1))
value_fetch_lazy (arg1);

if (value_lazy (arg1))
- set_value_lazy (v, 1);
+ v = allocate_value_lazy (value_enclosing_type (arg1));
else
- memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1),
- TYPE_LENGTH (value_enclosing_type (arg1)));
+ {
+ v = allocate_value (value_enclosing_type (arg1));
+ memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1),
+ TYPE_LENGTH (value_enclosing_type (arg1)));
+ }
+ v->type = type;
v->offset = value_offset (arg1);
v->embedded_offset = (offset + value_embedded_offset (arg1)
+ TYPE_FIELD_BITPOS (arg_type, fieldno) / 8);
@@ -1408,18 +1411,20 @@ value_primitive_field (struct value *arg
{
/* Plain old data member */
offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
- v = allocate_value (type);

/* Lazy register values with offsets are not supported. */
if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1))
value_fetch_lazy (arg1);

if (value_lazy (arg1))
- set_value_lazy (v, 1);
+ v = allocate_value_lazy (type);
else
- memcpy (value_contents_raw (v),
- value_contents_raw (arg1) + offset,
- TYPE_LENGTH (type));
+ {
+ v = allocate_value (type);
+ memcpy (value_contents_raw (v),
+ value_contents_raw (arg1) + offset,
+ TYPE_LENGTH (type));
+ }
v->offset = (value_offset (arg1) + offset
+ value_embedded_offset (arg1));
}
Index: valops.c
===================================================================
--- valops.c (revision 139003)
+++ valops.c (working copy)
@@ -608,11 +608,10 @@ value_at_lazy (struct type *type, CORE_A
if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID)
error (_("Attempt to dereference a generic pointer."));

- val = allocate_value (type);
+ val = allocate_value_lazy (type);

VALUE_LVAL (val) = lval_memory;
VALUE_ADDRESS (val) = addr;
- set_value_lazy (val, 1);

return val;
}
@@ -634,6 +633,8 @@ value_at_lazy (struct type *type, CORE_A
int
value_fetch_lazy (struct value *val)
{
+ gdb_assert (value_lazy (val));
+ allocate_value_contents (val);
if (VALUE_LVAL (val) == lval_memory)
{
CORE_ADDR addr = VALUE_ADDRESS (val) + value_offset (val);
@@ -1535,7 +1536,7 @@ search_struct_field (char *name, struct
if (BASETYPE_VIA_VIRTUAL (type, i))
{
int boffset;
- struct value *v2 = allocate_value (basetype);
+ struct value *v2;

boffset = baseclass_offset (type, i,
value_contents (arg1) + offset,
@@ -1553,6 +1554,7 @@ search_struct_field (char *name, struct
{
CORE_ADDR base_addr;

+ v2 = allocate_value (basetype);
base_addr =
VALUE_ADDRESS (arg1) + value_offset (arg1) + boffset;
if (target_read_memory (base_addr,
@@ -1564,16 +1566,19 @@ search_struct_field (char *name, struct
}
else
{
+ if (VALUE_LVAL (arg1) == lval_memory && value_lazy (arg1))
+ v2 = allocate_value_lazy (basetype);
+ else
+ {
+ v2 = allocate_value (basetype);
+ memcpy (value_contents_raw (v2),
+ value_contents_raw (arg1) + boffset,
+ TYPE_LENGTH (basetype));
+ }
VALUE_LVAL (v2) = VALUE_LVAL (arg1);
VALUE_ADDRESS (v2) = VALUE_ADDRESS (arg1);
VALUE_FRAME_ID (v2) = VALUE_FRAME_ID (arg1);
set_value_offset (v2, value_offset (arg1) + boffset);
- if (VALUE_LVAL (arg1) == lval_memory && value_lazy (arg1))
- set_value_lazy (v2, 1);
- else
- memcpy (value_contents_raw (v2),
- value_contents_raw (arg1) + boffset,
- TYPE_LENGTH (basetype));
}

if (found_baseclass)
@@ -2969,13 +2974,15 @@ value_slice (struct value *array, int lo
slice_range_type);
TYPE_CODE (slice_type) = TYPE_CODE (array_type);

- slice = allocate_value (slice_type);
if (VALUE_LVAL (array) == lval_memory && value_lazy (array))
- set_value_lazy (slice, 1);
+ slice = allocate_value_lazy (slice_type);
else
- memcpy (value_contents_writeable (slice),
- value_contents (array) + offset,
- TYPE_LENGTH (slice_type));
+ {
+ slice = allocate_value (slice_type);
+ memcpy (value_contents_writeable (slice),
+ value_contents (array) + offset,
+ TYPE_LENGTH (slice_type));
+ }

if (VALUE_LVAL (array) == lval_internalvar)
VALUE_LVAL (slice) = lval_internalvar_component;
Index: value.h
===================================================================
--- value.h (revision 139003)
+++ value.h (working copy)
@@ -314,6 +314,8 @@ extern struct value *locate_var_value (s
struct frame_info *frame);

extern struct value *allocate_value (struct type *type);
+extern struct value *allocate_value_lazy (struct type *type);
+extern void allocate_value_contents (struct value *value);

extern struct value *allocate_repeat_value (struct type *type, int count);

@@ -500,7 +502,7 @@ extern int unop_user_defined_p (enum exp

extern int destructor_name_p (const char *name, const struct type *type);

-#define value_free(val) xfree (val)
+extern void value_free (struct value *val);

extern void free_all_values (void);