giroffsets: Uniformly handle alignments as size_t

Do this by tracking the state of the size/alignment calculations
separately, rather than bunging it into the `alignment` field using
magic values.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3155
This commit is contained in:
Philip Withnall 2024-01-17 11:47:49 +00:00
parent 9fcec66115
commit 515b3fc1dc
2 changed files with 76 additions and 50 deletions

View File

@ -70,6 +70,27 @@ typedef enum
GI_IR_NODE_XREF = 19 GI_IR_NODE_XREF = 19
} GIIrNodeTypeId; } GIIrNodeTypeId;
/**
* GIIrOffsetsState:
* @GI_IR_OFFSETS_UNKNOWN: offsets have not been calculated yet
* @GI_IR_OFFSETS_COMPUTED: offsets have been successfully calculated
* @GI_IR_OFFSETS_FAILED: calculating the offsets failed
* @GI_IR_OFFSETS_IN_PROGRESS: offsets are currently being calculated (used to
* detect type recursion)
*
* State tracking for calculating size and alignment of
* [type@GIRepository.IrNode]s.
*
* Since: 2.80
*/
typedef enum
{
GI_IR_OFFSETS_UNKNOWN,
GI_IR_OFFSETS_COMPUTED,
GI_IR_OFFSETS_FAILED,
GI_IR_OFFSETS_IN_PROGRESS,
} GIIrOffsetsState;
struct _GIIrNode struct _GIIrNode
{ {
GIIrNodeTypeId type; GIIrNodeTypeId type;
@ -261,8 +282,9 @@ struct _GIIrNodeInterface
GList *interfaces; GList *interfaces;
GList *prerequisites; GList *prerequisites;
gssize alignment; size_t alignment;
size_t size; size_t size;
GIIrOffsetsState offsets_state;
GList *members; GList *members;
}; };
@ -311,8 +333,9 @@ struct _GIIrNodeBoxed
char *gtype_name; char *gtype_name;
char *gtype_init; char *gtype_init;
gssize alignment; size_t alignment;
size_t size; size_t size;
GIIrOffsetsState offsets_state;
GList *members; GList *members;
}; };
@ -334,8 +357,9 @@ struct _GIIrNodeStruct
char *copy_func; char *copy_func;
char *free_func; char *free_func;
gssize alignment; size_t alignment;
size_t size; size_t size;
GIIrOffsetsState offsets_state;
GList *members; GList *members;
}; };
@ -355,8 +379,9 @@ struct _GIIrNodeUnion
char *copy_func; char *copy_func;
char *free_func; char *free_func;
gssize alignment; size_t alignment;
size_t size; size_t size;
GIIrOffsetsState offsets_state;
int discriminator_offset; int discriminator_offset;
GIIrNodeType *discriminator_type; GIIrNodeType *discriminator_type;

View File

@ -150,7 +150,7 @@ compute_enum_storage_type (GIIrNodeEnum *enum_node)
static gboolean static gboolean
get_enum_size_alignment (GIIrNodeEnum *enum_node, get_enum_size_alignment (GIIrNodeEnum *enum_node,
size_t *size, size_t *size,
gssize *alignment) size_t *alignment)
{ {
ffi_type *type_ffi; ffi_type *type_ffi;
@ -189,7 +189,7 @@ static gboolean
get_interface_size_alignment (GIIrTypelibBuild *build, get_interface_size_alignment (GIIrTypelibBuild *build,
GIIrNodeType *type, GIIrNodeType *type,
size_t *size, size_t *size,
gssize *alignment, size_t *alignment,
const char *who) const char *who)
{ {
GIIrNode *iface; GIIrNode *iface;
@ -198,8 +198,8 @@ get_interface_size_alignment (GIIrTypelibBuild *build,
if (!iface) if (!iface)
{ {
gi_ir_module_fatal (build, 0, "Can't resolve type '%s' for %s", type->giinterface, who); gi_ir_module_fatal (build, 0, "Can't resolve type '%s' for %s", type->giinterface, who);
*size = -1; *size = 0;
*alignment = -1; *alignment = 0;
return FALSE; return FALSE;
} }
@ -253,9 +253,9 @@ get_interface_size_alignment (GIIrTypelibBuild *build,
g_warning ("%s has is not a pointer and is of type %s", g_warning ("%s has is not a pointer and is of type %s",
who, who,
gi_ir_node_type_to_string (iface->type)); gi_ir_node_type_to_string (iface->type));
*size = -1; *size = 0;
*alignment = -1; *alignment = 0;
break; return FALSE;
} }
} }
@ -266,7 +266,7 @@ static gboolean
get_type_size_alignment (GIIrTypelibBuild *build, get_type_size_alignment (GIIrTypelibBuild *build,
GIIrNodeType *type, GIIrNodeType *type,
size_t *size, size_t *size,
gssize *alignment, size_t *alignment,
const char *who) const char *who)
{ {
ffi_type *type_ffi; ffi_type *type_ffi;
@ -278,14 +278,14 @@ get_type_size_alignment (GIIrTypelibBuild *build,
else if (type->tag == GI_TYPE_TAG_ARRAY) else if (type->tag == GI_TYPE_TAG_ARRAY)
{ {
size_t elt_size; size_t elt_size;
gssize elt_alignment; size_t elt_alignment;
if (!type->has_size if (!type->has_size
|| !get_type_size_alignment(build, type->parameter_type1, || !get_type_size_alignment(build, type->parameter_type1,
&elt_size, &elt_alignment, who)) &elt_size, &elt_alignment, who))
{ {
*size = -1; *size = 0;
*alignment = -1; *alignment = 0;
return FALSE; return FALSE;
} }
@ -307,8 +307,8 @@ get_type_size_alignment (GIIrTypelibBuild *build,
if (type_ffi == &ffi_type_void) if (type_ffi == &ffi_type_void)
{ {
g_warning ("%s has void type", who); g_warning ("%s has void type", who);
*size = -1; *size = 0;
*alignment = -1; *alignment = 0;
return FALSE; return FALSE;
} }
else if (type_ffi == &ffi_type_pointer) else if (type_ffi == &ffi_type_pointer)
@ -316,8 +316,8 @@ get_type_size_alignment (GIIrTypelibBuild *build,
g_warning ("%s has is not a pointer and is of type %s", g_warning ("%s has is not a pointer and is of type %s",
who, who,
gi_type_tag_to_string (type->tag)); gi_type_tag_to_string (type->tag));
*size = -1; *size = 0;
*alignment = -1; *alignment = 0;
return FALSE; return FALSE;
} }
} }
@ -335,7 +335,7 @@ get_field_size_alignment (GIIrTypelibBuild *build,
GIIrNodeField *field, GIIrNodeField *field,
GIIrNode *parent_node, GIIrNode *parent_node,
size_t *size, size_t *size,
gssize *alignment) size_t *alignment)
{ {
GIIrModule *module = build->module; GIIrModule *module = build->module;
char *who; char *who;
@ -363,14 +363,15 @@ compute_struct_field_offsets (GIIrTypelibBuild *build,
GIIrNode *node, GIIrNode *node,
GList *members, GList *members,
size_t *size_out, size_t *size_out,
gssize *alignment_out) size_t *alignment_out,
GIIrOffsetsState *offsets_state_out)
{ {
int size = 0; size_t size = 0;
int alignment = 1; size_t alignment = 1;
GList *l; GList *l;
gboolean have_error = FALSE; gboolean have_error = FALSE;
*alignment_out = -2; /* mark to detect recursion */ *offsets_state_out = GI_IR_OFFSETS_IN_PROGRESS; /* mark to detect recursion */
for (l = members; l; l = l->next) for (l = members; l; l = l->next)
{ {
@ -383,7 +384,7 @@ compute_struct_field_offsets (GIIrTypelibBuild *build,
if (!have_error) if (!have_error)
{ {
size_t member_size; size_t member_size;
gssize member_alignment; size_t member_alignment;
if (get_field_size_alignment (build, field, node, if (get_field_size_alignment (build, field, node,
&member_size, &member_alignment)) &member_size, &member_alignment))
@ -415,11 +416,13 @@ compute_struct_field_offsets (GIIrTypelibBuild *build,
{ {
*size_out = size; *size_out = size;
*alignment_out = alignment; *alignment_out = alignment;
*offsets_state_out = GI_IR_OFFSETS_COMPUTED;
} }
else else
{ {
*size_out = -1; *size_out = 0;
*alignment_out = -1; *alignment_out = 0;
*offsets_state_out = GI_IR_OFFSETS_FAILED;
} }
return !have_error; return !have_error;
@ -430,14 +433,15 @@ compute_union_field_offsets (GIIrTypelibBuild *build,
GIIrNode *node, GIIrNode *node,
GList *members, GList *members,
size_t *size_out, size_t *size_out,
gssize *alignment_out) size_t *alignment_out,
GIIrOffsetsState *offsets_state_out)
{ {
size_t size = 0; size_t size = 0;
int alignment = 1; size_t alignment = 1;
GList *l; GList *l;
gboolean have_error = FALSE; gboolean have_error = FALSE;
*alignment_out = -2; /* mark to detect recursion */ *offsets_state_out = GI_IR_OFFSETS_IN_PROGRESS; /* mark to detect recursion */
for (l = members; l; l = l->next) for (l = members; l; l = l->next)
{ {
@ -450,7 +454,7 @@ compute_union_field_offsets (GIIrTypelibBuild *build,
if (!have_error) if (!have_error)
{ {
size_t member_size; size_t member_size;
gssize member_alignment; size_t member_alignment;
if (get_field_size_alignment (build,field, node, if (get_field_size_alignment (build,field, node,
&member_size, &member_alignment)) &member_size, &member_alignment))
@ -471,11 +475,13 @@ compute_union_field_offsets (GIIrTypelibBuild *build,
{ {
*size_out = size; *size_out = size;
*alignment_out = alignment; *alignment_out = alignment;
*offsets_state_out = GI_IR_OFFSETS_COMPUTED;
} }
else else
{ {
*size_out = -1; *size_out = 0;
*alignment_out = -1; *alignment_out = 0;
*offsets_state_out = GI_IR_OFFSETS_FAILED;
} }
return !have_error; return !have_error;
@ -484,22 +490,17 @@ compute_union_field_offsets (GIIrTypelibBuild *build,
static gboolean static gboolean
check_needs_computation (GIIrTypelibBuild *build, check_needs_computation (GIIrTypelibBuild *build,
GIIrNode *node, GIIrNode *node,
int alignment) GIIrOffsetsState offsets_state)
{ {
GIIrModule *module = build->module; GIIrModule *module = build->module;
/*
* 0: Not yet computed if (offsets_state == GI_IR_OFFSETS_IN_PROGRESS)
* >0: Previously succeeded
* -1: Previously failed
* -2: In progress
*/
if (alignment == -2)
{ {
g_warning ("Recursion encountered when computing the size of %s.%s", g_warning ("Recursion encountered when computing the size of %s.%s",
module->name, node->name); module->name, node->name);
} }
return alignment == 0; return offsets_state == GI_IR_OFFSETS_UNKNOWN;
} }
/* /*
@ -532,22 +533,22 @@ gi_ir_node_compute_offsets (GIIrTypelibBuild *build,
{ {
GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node;
if (!check_needs_computation (build, node, boxed->alignment)) if (!check_needs_computation (build, node, boxed->offsets_state))
return; return;
compute_struct_field_offsets (build, node, boxed->members, compute_struct_field_offsets (build, node, boxed->members,
&boxed->size, &boxed->alignment); &boxed->size, &boxed->alignment, &boxed->offsets_state);
break; break;
} }
case GI_IR_NODE_STRUCT: case GI_IR_NODE_STRUCT:
{ {
GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node;
if (!check_needs_computation (build, node, struct_->alignment)) if (!check_needs_computation (build, node, struct_->offsets_state))
return; return;
compute_struct_field_offsets (build, node, struct_->members, compute_struct_field_offsets (build, node, struct_->members,
&struct_->size, &struct_->alignment); &struct_->size, &struct_->alignment, &struct_->offsets_state);
break; break;
} }
case GI_IR_NODE_OBJECT: case GI_IR_NODE_OBJECT:
@ -555,22 +556,22 @@ gi_ir_node_compute_offsets (GIIrTypelibBuild *build,
{ {
GIIrNodeInterface *iface = (GIIrNodeInterface *)node; GIIrNodeInterface *iface = (GIIrNodeInterface *)node;
if (!check_needs_computation (build, node, iface->alignment)) if (!check_needs_computation (build, node, iface->offsets_state))
return; return;
compute_struct_field_offsets (build, node, iface->members, compute_struct_field_offsets (build, node, iface->members,
&iface->size, &iface->alignment); &iface->size, &iface->alignment, &iface->offsets_state);
break; break;
} }
case GI_IR_NODE_UNION: case GI_IR_NODE_UNION:
{ {
GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; GIIrNodeUnion *union_ = (GIIrNodeUnion *)node;
if (!check_needs_computation (build, node, union_->alignment)) if (!check_needs_computation (build, node, union_->offsets_state))
return; return;
compute_union_field_offsets (build, (GIIrNode*)union_, union_->members, compute_union_field_offsets (build, (GIIrNode*)union_, union_->members,
&union_->size, &union_->alignment); &union_->size, &union_->alignment, &union_->offsets_state);
break; break;
} }
case GI_IR_NODE_ENUM: case GI_IR_NODE_ENUM: