libctf: eliminate dtd_u, part 5: structs / unions

Eliminate the dynamic member storage for structs and unions as we have
for other dynamic types.  This is much like the previous enum
elimination, except that structs and unions are the only types for which
a full-sized ctf_type_t might be needed.  Up to now, this decision has
been made in the individual ctf_add_{struct,union}_sized functions and
duplicated in ctf_add_member_offset.  The vlen machinery lets us
simplify this, always allocating a ctf_lmember_t and setting the
dtd_data's ctt_size to CTF_LSIZE_SENT: we figure out whether this is
really justified and (almost always) repack things down into a
ctf_stype_t at ctf_serialize time.

This allows us to eliminate the dynamic member paths from the iterators and
query functions in ctf-types.c in favour of always using the large-structure
vlen stuff for dynamic types (the diff is ugly but that's just because of the
volume of reindentation this calls for).  This also means the large-structure
vlen stuff gets more heavily tested, which is nice because it was an almost
totally unused code path before now (it only kicked in for structures of size
>4GiB, and how often do you see those?)

The only extra complexity here is ctf_add_type.  Back in the days of the
nondeduplicating linker this was called a ridiculous number of times for
countless identical copies of structures: eschewing the repeated lookups of the
dtd in ctf_add_member_offset and adding the members directly saved an amazing
amount of time.  Now the nondeduplicating linker is gone, this is extreme
overoptimization: we can rip out the direct addition and use ctf_member_next and
ctf_add_member_offset, just like ctf_dedup_emit does.

We augment a ctf_add_type test to try adding a self-referential struct, the only
thing the ctf_add_type part of this change really perturbs.

This completes the elimination of dtd_u.

libctf/ChangeLog
2021-03-18  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dtdef_t) <dtu_members>: Remove.
	<dtd_u>: Likewise.
	(ctf_dmdef_t): Remove.
	(struct ctf_next) <u.ctn_dmd>: Remove.
	* ctf-create.c (INITIAL_VLEN): New, more-or-less arbitrary initial
	vlen size.
	(ctf_add_enum): Use it.
	(ctf_dtd_delete): Do not free the (removed) dmd; remove string
	refs from the vlen on struct deletion.
	(ctf_add_struct_sized): Populate the vlen: do it by hand if
	promoting forwards.  Always populate the full-size
	lsizehi/lsizelo members.
	(ctf_add_union_sized): Likewise.
	(ctf_add_member_offset): Set up the vlen rather than the dmd.
	Expand it as needed, repointing string refs via
	ctf_str_move_pending. Add the member names as pending strings.
	Always populate the full-size lsizehi/lsizelo members.
	(membadd): Remove, folding back into...
	(ctf_add_type_internal): ... here, adding via an ordinary
	ctf_add_struct_sized and _next iteration rather than doing
	everything by hand.
	* ctf-serialize.c (ctf_copy_smembers): Remove this...
	(ctf_copy_lmembers): ... and this...
	(ctf_emit_type_sect): ... folding into here. Figure out if a
	ctf_stype_t is needed here, not in ctf_add_*_sized.
	(ctf_type_sect_size): Figure out the ctf_stype_t stuff the same
	way here.
	* ctf-types.c (ctf_member_next): Remove the dmd path and always
	use the vlen.  Force large-structure usage for dynamic types.
	(ctf_type_align): Likewise.
	(ctf_member_info): Likewise.
	(ctf_type_rvisit): Likewise.
	* testsuite/libctf-regression/type-add-unnamed-struct-ctf.c: Add a
	self-referential type to this test.
	* testsuite/libctf-regression/type-add-unnamed-struct.c: Adjusted
	accordingly.
	* testsuite/libctf-regression/type-add-unnamed-struct.lk: Likewise.
This commit is contained in:
Nick Alcock 2021-03-18 12:37:52 +00:00
parent 77d724a7ec
commit 08c428aff4
8 changed files with 327 additions and 414 deletions

View file

@ -101,24 +101,17 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
dtd = ctf_dynamic_type (fp, type);
i->ctn_iter_fun = (void (*) (void)) ctf_member_next;
/* We depend below on the RDWR state indicating whether the DTD-related
fields or the DMD-related fields have been initialized. */
assert ((dtd && (fp->ctf_flags & LCTF_RDWR))
|| (!dtd && (!(fp->ctf_flags & LCTF_RDWR))));
i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
if (dtd == NULL)
{
i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
if (i->ctn_size < CTF_LSTRUCT_THRESH)
i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + increment);
else
i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + increment);
}
else
i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
i->u.ctn_lmp = (const ctf_lmember_t *) dtd->dtd_vlen;
*it = i;
}
@ -141,71 +134,46 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
retry:
if (!i->ctn_type)
{
if (!(fp->ctf_flags & LCTF_RDWR))
if (i->ctn_n == 0)
goto end_iter;
/* Dynamic structures in read-write dicts always use lmembers. */
if (i->ctn_size < CTF_LSTRUCT_THRESH
&& !(fp->ctf_flags & LCTF_RDWR))
{
if (i->ctn_n == 0)
goto end_iter;
const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
if (i->ctn_size < CTF_LSTRUCT_THRESH)
{
const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
if (name)
*name = membname;
if (membtype)
*membtype = i->u.ctn_mp->ctm_type;
offset = i->u.ctn_mp->ctm_offset;
if (name)
*name = membname;
if (membtype)
*membtype = i->u.ctn_mp->ctm_type;
offset = i->u.ctn_mp->ctm_offset;
if (membname[0] == 0
&& (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION))
i->ctn_type = i->u.ctn_mp->ctm_type;
if (membname[0] == 0
&& (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION))
i->ctn_type = i->u.ctn_mp->ctm_type;
i->u.ctn_mp++;
}
else
{
const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
if (name)
*name = membname;
if (membtype)
*membtype = i->u.ctn_lmp->ctlm_type;
offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
if (membname[0] == 0
&& (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION))
i->ctn_type = i->u.ctn_lmp->ctlm_type;
i->u.ctn_lmp++;
}
i->ctn_n--;
i->u.ctn_mp++;
}
else
{
if (i->u.ctn_dmd == NULL)
goto end_iter;
/* The dmd contains a NULL for unnamed dynamic members. Don't inflict
this on our callers. */
const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
if (name)
{
if (i->u.ctn_dmd->dmd_name)
*name = i->u.ctn_dmd->dmd_name;
else
*name = "";
}
*name = membname;
if (membtype)
*membtype = i->u.ctn_dmd->dmd_type;
offset = i->u.ctn_dmd->dmd_offset;
*membtype = i->u.ctn_lmp->ctlm_type;
offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
if (i->u.ctn_dmd->dmd_name == NULL
&& (ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_UNION))
i->ctn_type = i->u.ctn_dmd->dmd_type;
if (membname[0] == 0
&& (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION))
i->ctn_type = i->u.ctn_lmp->ctlm_type;
i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd);
i->u.ctn_lmp++;
}
i->ctn_n--;
/* The callers might want automatic recursive sub-struct traversal. */
if (!(flags & CTF_MN_RECURSE))
@ -996,53 +964,44 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
case CTF_K_UNION:
{
size_t align = 0;
int dynamic = 0;
ctf_dtdef_t *dtd;
if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
dynamic = 1;
uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info);
ssize_t size, increment;
const void *vmp;
(void) ctf_get_ctt_size (fp, tp, &size, &increment);
if (!dynamic)
vmp = (unsigned char *) tp + increment;
else
vmp = dtd->dtd_vlen;
if (kind == CTF_K_STRUCT)
n = MIN (n, 1); /* Only use first member for structs. */
if (size < CTF_LSTRUCT_THRESH && !dynamic)
{
uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info);
ssize_t size, increment;
const void *vmp;
(void) ctf_get_ctt_size (fp, tp, &size, &increment);
vmp = (unsigned char *) tp + increment;
if (kind == CTF_K_STRUCT)
n = MIN (n, 1); /* Only use first member for structs. */
if (size < CTF_LSTRUCT_THRESH)
const ctf_member_t *mp = vmp;
for (; n != 0; n--, mp++)
{
const ctf_member_t *mp = vmp;
for (; n != 0; n--, mp++)
{
ssize_t am = ctf_type_align (ofp, mp->ctm_type);
align = MAX (align, (size_t) am);
}
}
else
{
const ctf_lmember_t *lmp = vmp;
for (; n != 0; n--, lmp++)
{
ssize_t am = ctf_type_align (ofp, lmp->ctlm_type);
align = MAX (align, (size_t) am);
}
ssize_t am = ctf_type_align (ofp, mp->ctm_type);
align = MAX (align, (size_t) am);
}
}
else
{
ctf_dmdef_t *dmd;
for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
dmd != NULL; dmd = ctf_list_next (dmd))
{
ssize_t am = ctf_type_align (ofp, dmd->dmd_type);
align = MAX (align, (size_t) am);
if (kind == CTF_K_STRUCT)
break;
}
const ctf_lmember_t *lmp = vmp;
for (; n != 0; n--, lmp++)
{
ssize_t am = ctf_type_align (ofp, lmp->ctlm_type);
align = MAX (align, (size_t) am);
}
}
return align;
}
@ -1390,8 +1349,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
ctf_dict_t *ofp = fp;
const ctf_type_t *tp;
ctf_dtdef_t *dtd;
const void *vmp;
ssize_t size, increment;
uint32_t kind, n;
int dynamic = 0;
if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
return -1; /* errno is set for us. */
@ -1405,73 +1366,54 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
return (ctf_set_errno (ofp, ECTF_NOTSOU));
if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
dynamic = 1;
if (!dynamic)
vmp = (unsigned char *) tp + increment;
else
vmp = dtd->dtd_vlen;
if (size < CTF_LSTRUCT_THRESH && !dynamic)
{
if (size < CTF_LSTRUCT_THRESH)
const ctf_member_t *mp = vmp;
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
{
const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
increment);
const char *membname = ctf_strptr (fp, mp->ctm_name);
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
if (membname[0] == 0
&& (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION)
&& (ctf_member_info (fp, mp->ctm_type, name, mip) == 0))
return 0;
if (strcmp (membname, name) == 0)
{
const char *membname = ctf_strptr (fp, mp->ctm_name);
if (membname[0] == 0
&& (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION)
&& (ctf_member_info (fp, mp->ctm_type, name, mip) == 0))
return 0;
if (strcmp (membname, name) == 0)
{
mip->ctm_type = mp->ctm_type;
mip->ctm_offset = mp->ctm_offset;
return 0;
}
}
}
else
{
const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
increment);
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
{
const char *membname = ctf_strptr (fp, lmp->ctlm_name);
if (membname[0] == 0
&& (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION)
&& (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0))
return 0;
if (strcmp (membname, name) == 0)
{
mip->ctm_type = lmp->ctlm_type;
mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
return 0;
}
mip->ctm_type = mp->ctm_type;
mip->ctm_offset = mp->ctm_offset;
return 0;
}
}
}
else
{
ctf_dmdef_t *dmd;
const ctf_lmember_t *lmp = vmp;
for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
dmd != NULL; dmd = ctf_list_next (dmd))
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
{
if (dmd->dmd_name == NULL
&& (ctf_type_kind (fp, dmd->dmd_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, dmd->dmd_type) == CTF_K_UNION)
&& (ctf_member_info (fp, dmd->dmd_type, name, mip) == 0))
const char *membname = ctf_strptr (fp, lmp->ctlm_name);
if (membname[0] == 0
&& (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT
|| ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION)
&& (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0))
return 0;
if (dmd->dmd_name != NULL
&& strcmp (dmd->dmd_name, name) == 0)
if (strcmp (membname, name) == 0)
{
mip->ctm_type = dmd->dmd_type;
mip->ctm_offset = dmd->dmd_offset;
mip->ctm_type = lmp->ctlm_type;
mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
return 0;
}
}
@ -1688,8 +1630,10 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
ctf_id_t otype = type;
const ctf_type_t *tp;
const ctf_dtdef_t *dtd;
const void *vmp;
ssize_t size, increment;
uint32_t kind, n;
int dynamic = 0;
int rc;
if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
@ -1708,48 +1652,38 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
(void) ctf_get_ctt_size (fp, tp, &size, &increment);
if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
dynamic = 1;
if (!dynamic)
vmp = (unsigned char *) tp + increment;
else
vmp = dtd->dtd_vlen;
if (size < CTF_LSTRUCT_THRESH && !dynamic)
{
if (size < CTF_LSTRUCT_THRESH)
{
const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
increment);
const ctf_member_t *mp = vmp;
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
{
if ((rc = ctf_type_rvisit (fp, mp->ctm_type,
func, arg, ctf_strptr (fp,
mp->ctm_name),
offset + mp->ctm_offset,
depth + 1)) != 0)
return rc;
}
}
else
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
{
const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
increment);
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
{
if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type,
func, arg, ctf_strptr (fp,
lmp->ctlm_name),
offset + (unsigned long) CTF_LMEM_OFFSET (lmp),
depth + 1)) != 0)
return rc;
}
if ((rc = ctf_type_rvisit (fp, mp->ctm_type,
func, arg, ctf_strptr (fp,
mp->ctm_name),
offset + mp->ctm_offset,
depth + 1)) != 0)
return rc;
}
}
else
{
ctf_dmdef_t *dmd;
const ctf_lmember_t *lmp = vmp;
for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
dmd != NULL; dmd = ctf_list_next (dmd))
for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
{
if ((rc = ctf_type_rvisit (fp, dmd->dmd_type, func, arg,
dmd->dmd_name, dmd->dmd_offset,
if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type,
func, arg, ctf_strptr (fp,
lmp->ctlm_name),
offset + (unsigned long) CTF_LMEM_OFFSET (lmp),
depth + 1)) != 0)
return rc;
}