in benchmarks/JetStream2/wasm/TSF/tsf_gpc_code_gen.c [2992:3129]
static tsf_bool_t generate_destroyer(gpc_proto_t *proto,
tsf_type_t *type,
gpc_cell_t offset,
gpc_cell_t label) {
uint32_t i;
gpc_cell_t label_offset;
gpc_cell_t done_label, really_done_label;
gpc_cell_t *targets;
tsf_bool_t result;
switch (type->kind_code) {
case TSF_TK_STRUCT:
/* If the struct has a destructor, assume that it will destroy all of the fields,
including the ones that we know about. */
if (type->u.s.destructor != NULL) {
C(append(proto, GPC_I_CALL,
offset,
type->u.s.destructor));
} else {
if (type->u.s.pre_destructor != NULL) {
C(append(proto, GPC_I_CALL,
offset,
type->u.s.pre_destructor));
}
for (i = 0; i < tsf_struct_type_get_num_elements(type); ++i) {
tsf_named_type_t *n = tsf_struct_type_get_element(type, i);
if (n->type->kind_code == TSF_TK_BIT) {
continue;
}
C(generate_destroyer(proto,
n->type,
offset + n->offset,
label));
}
}
break;
case TSF_TK_ARRAY:
if (type->u.a.element_type->kind_code == TSF_TK_VOID) {
/* Nothing to do - a void array isn't really a container. */
} else if (type->u.a.element_type->kind_code == TSF_TK_BIT) {
C(append(proto,
GPC_I_FREE,
offset + tsf_offsetof(tsf_native_bitvector_t, bits)));
} else {
if (needs_destruction(type->u.a.element_type)) {
gpc_cell_t loop_label = label++;
done_label = label++;
C(append(proto,
GPC_I_PUSH_PTR,
offset + tsf_offsetof(tsf_native_array_t, data)));
C(append(proto,
GPC_I_REPUSH_MULADD_PTR,
offset + tsf_offsetof(tsf_native_array_t, len),
tsf_native_type_get_size(type->u.a.element_type)));
C(append(proto, GPC_I_COMPFAILJUMP, done_label));
C(append(proto, GPC_I_LABEL, loop_label));
C(generate_destroyer(proto, type->u.a.element_type, 0, label));
C(append(proto,
GPC_I_ADDCOMPJUMP,
tsf_native_type_get_size(type->u.a.element_type),
loop_label));
C(append(proto, GPC_I_LABEL, done_label));
C(append(proto, GPC_I_TWO_POP));
}
C(append(proto, GPC_I_FREE, offset + tsf_offsetof(tsf_native_array_t, data)));
}
break;
case TSF_TK_CHOICE:
if (tsf_choice_type_has_non_void(type)) {
label_offset = label;
label += tsf_choice_type_get_num_elements(type);
done_label = label++;
really_done_label = label++;
targets=malloc(sizeof(gpc_cell_t)*
tsf_choice_type_get_num_elements(type));
if (targets == NULL) {
tsf_set_errno("Could not malloc array of "
"gpc_cell_t");
return tsf_false;
}
for (i = 0; i < tsf_choice_type_get_num_elements(type); ++i) {
targets[i] = label_offset + i;
}
result=append_tablejump_field(
proto,
offset + type->u.h.value_offset,
tsf_choice_type_get_num_elements(type),
targets);
free(targets);
if (!result) {
return tsf_false;
}
C(append(proto, GPC_I_JUMP, really_done_label)); /* for unknown values */
for (i = 0; i < tsf_choice_type_get_num_elements(type); ++i) {
tsf_named_type_t *n = tsf_choice_type_get_element(type, i);
C(append(proto, GPC_I_LABEL, label_offset + i));
if (tsf_native_choice_type_is_in_place(type)) {
C(generate_destroyer(proto,
n->type,
offset + type->u.h.data_offset,
label));
} else {
/* cannot move this push above the tablejump since the
tablejump uses the value at the top of the stack, and
I don't feel like adding a second tablejump just to
get around that. */
C(append(proto, GPC_I_PUSH_PTR,
offset + type->u.h.data_offset));
C(generate_destroyer(proto,
n->type,
0,
label));
}
C(append(proto, GPC_I_JUMP, done_label));
}
/* if it is in place, you get two labels... oh well. */
C(append(proto, GPC_I_LABEL, done_label));
if (!tsf_native_choice_type_is_in_place(type)) {
C(append(proto, GPC_I_FREE_IMMEDIATE));
C(append(proto, GPC_I_POP));
}
C(append(proto, GPC_I_LABEL, really_done_label));
}
break;
case TSF_TK_STRING:
C(append(proto, GPC_I_FREE, offset));
break;
case TSF_TK_ANY:
C(append(proto, GPC_I_DESTROY_BUFFER, offset));
break;
default:
/* None of the other types have things that need to be freed. */
break;
}
return tsf_true;
}