static tsf_bool_t generate_destroyer()

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;
}