| /* |
| * Copyright (C) 2003, 2004, 2005, 2007, 2014, 2015 Filip Pizlo. All rights reserved. |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY FILIP PIZLO ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FILIP PIZLO OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "tsf_internal.h" |
| #include "gpc.h" |
| |
| #include <math.h> |
| |
| #define C(exp) do { \ |
| if (!(exp)) { \ |
| return tsf_false; \ |
| } \ |
| } while(0) |
| |
| #define append gpc_proto_append |
| #define append_tableset_local_to_field \ |
| gpc_proto_append_tableset_local_to_field |
| #define append_tableset_field_to_field \ |
| gpc_proto_append_tableset_field_to_field |
| #define append_tablejump_local gpc_proto_append_tablejump_local |
| #define append_tablejump_field gpc_proto_append_tablejump_field |
| |
| static tsf_bool_t generate_size_calc(gpc_proto_t *proto, |
| tsf_type_t *type, |
| gpc_cell_t offset, |
| gpc_cell_t label) { |
| uint32_t i; |
| uint32_t num_bits = 0; |
| gpc_cell_t label_offset; |
| gpc_cell_t done_label, really_done_label; |
| gpc_cell_t *targets; |
| tsf_bool_t result; |
| |
| gpc_cell_t static_size = tsf_type_get_static_size(type); |
| if (static_size != UINT32_MAX) { |
| if (static_size != 0) { |
| C(append(proto, GPC_I_INC_SIZE, static_size)); |
| } |
| |
| return tsf_true; |
| } |
| |
| switch (type->kind_code) { |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_TSF_INTEGER_SIZE, offset)); |
| break; |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_TSF_LONG_SIZE, offset)); |
| break; |
| case TSF_TK_STRUCT: |
| 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) { |
| ++num_bits; |
| continue; |
| } |
| C(generate_size_calc(proto, |
| n->type, |
| offset + n->offset, |
| label)); |
| } |
| if (num_bits != 0) { |
| C(append(proto, |
| GPC_I_INC_SIZE, |
| (gpc_cell_t)((num_bits + 7) >> 3))); |
| } |
| break; |
| case TSF_TK_ARRAY: |
| if (type->u.a.element_type->kind_code == TSF_TK_VOID) { |
| C(append(proto, |
| GPC_I_INC_SIZE_ARRAY_LEN, |
| offset + tsf_offsetof(tsf_native_void_array_t, len))); |
| } else if (type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| C(append(proto, |
| GPC_I_INC_SIZE_BITVECTOR, |
| offset)); |
| } else { |
| static_size = tsf_type_get_static_size(type->u.a.element_type); |
| if (static_size == UINT32_MAX) { |
| gpc_cell_t loop_label = label++; |
| done_label = label++; |
| |
| C(append(proto, |
| GPC_I_INC_SIZE_ARRAY_LEN, |
| offset + tsf_offsetof(tsf_native_array_t, |
| len))); |
| 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_size_calc(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)); |
| } else { |
| C(append(proto, |
| GPC_I_INC_SIZE_ARRAY, |
| offset, |
| (gpc_cell_t)static_size)); |
| } |
| } |
| break; |
| case TSF_TK_CHOICE: |
| tsf_assert(tsf_choice_type_has_non_void(type) || |
| (tsf_choice_type_get_num_elements(type) >= 256 && |
| !type->u.h.choice_as_full_word)); |
| if (tsf_choice_type_get_num_elements(type) >= 256) { |
| if (type->u.h.choice_as_full_word) { |
| C(append(proto, GPC_I_INC_SIZE, 4)); |
| } else { |
| C(append(proto, GPC_I_TSF_UNSIGNED_PLUS1_SIZE, |
| offset + type->u.h.value_offset)); |
| } |
| } else { |
| C(append(proto, GPC_I_INC_SIZE, 1)); |
| } |
| 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_size_calc(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_size_calc(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_POP)); |
| } |
| C(append(proto, GPC_I_LABEL, really_done_label)); |
| } |
| break; |
| case TSF_TK_STRING: |
| C(append(proto, GPC_I_STRING_SIZE, offset)); |
| break; |
| case TSF_TK_ANY: |
| C(append(proto, GPC_I_ANY_SIZE, offset)); |
| break; |
| default: |
| tsf_abort("Types other than struct, array, and choice " |
| "should have static size!"); |
| break; |
| } |
| |
| return tsf_true; |
| } |
| |
| static tsf_bool_t generate_generator(gpc_proto_t *proto, |
| tsf_type_t *type, |
| gpc_cell_t offset, |
| gpc_cell_t label) { |
| uint32_t i; |
| uint32_t bit = 0; |
| gpc_cell_t done_label, really_done_label; |
| |
| switch (type->kind_code) { |
| case TSF_TK_VOID: |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_HTONC_INCDST, |
| offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_HTONS_INCDST, |
| offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| C(append(proto, |
| GPC_I_COPY_HTONL_INCDST, |
| offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| C(append(proto, |
| GPC_I_COPY_HTONLL_INCDST, |
| offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_HTONF_INCDST, |
| offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_HTOND_INCDST, |
| offset)); |
| break; |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_BIT_WRITE, |
| offset)); |
| break; |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_TSF_INTEGER_WRITE, offset)); |
| break; |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_TSF_LONG_WRITE, offset)); |
| break; |
| case TSF_TK_STRUCT: |
| 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_generator(proto, |
| n->type, |
| offset + n->offset, |
| label)); |
| } |
| 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(append(proto, |
| GPC_I_BIT_MASK_WRITE, |
| bit, |
| offset + n->offset)); |
| ++bit; |
| if (bit == 8) { |
| bit = 0; |
| C(append(proto, GPC_I_SKIP, 1)); |
| } |
| } |
| if (bit) { |
| C(append(proto, GPC_I_SKIP, 1)); |
| } |
| break; |
| case TSF_TK_ARRAY: |
| if (type->u.a.element_type->kind_code == TSF_TK_VOID) { |
| C(append(proto, |
| GPC_I_ARRAY_LEN_WRITE_FIELD, |
| offset + tsf_offsetof(tsf_native_void_array_t, |
| len))); |
| } else if (type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| C(append(proto, |
| GPC_I_BITVECTOR_WRITE, |
| offset)); |
| } else if (type->u.a.element_type->kind_code == TSF_TK_UINT8 || |
| type->u.a.element_type->kind_code == TSF_TK_INT8 |
| #ifndef NEED_INT_CONVERSION |
| || tsf_type_kind_is_int( |
| type->u.a.element_type->kind_code) |
| #endif |
| #ifndef NEED_FLOAT_CONVERSION |
| || tsf_type_kind_is_float( |
| type->u.a.element_type->kind_code) |
| #endif |
| ) { |
| C(append(proto, |
| GPC_I_BYTE_ARRAY_WRITE, |
| offset, |
| tsf_native_type_get_size( |
| type->u.a.element_type))); |
| } else { |
| gpc_cell_t loop_label = label++; |
| done_label = label++; |
| |
| C(append(proto, |
| GPC_I_ARRAY_LEN_WRITE_FIELD, |
| offset + tsf_offsetof(tsf_native_array_t, |
| len))); |
| |
| 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_generator(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)); |
| } |
| break; |
| case TSF_TK_CHOICE: |
| if (tsf_choice_type_get_num_elements(type) >= 256) { |
| if (type->u.h.choice_as_full_word) { |
| C(append(proto, |
| GPC_I_COPY_HTONL_INCDST, |
| offset + type->u.h.value_offset)); |
| } else { |
| C(append(proto, |
| GPC_I_TSF_UNSIGNED_PLUS1_WRITE, |
| offset + type->u.h.value_offset)); |
| } |
| } else { |
| C(append(proto, |
| GPC_I_COPY_HTONCHOICE_TO_UI8_INCDST, |
| offset + type->u.h.value_offset)); |
| } |
| if (tsf_choice_type_has_non_void(type)) { |
| gpc_cell_t *targets; |
| gpc_cell_t label_offset; |
| tsf_bool_t result; |
| |
| 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; |
| } |
| |
| /* for unknown values */ |
| C(append(proto, GPC_I_JUMP, really_done_label)); |
| |
| 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_generator(proto, |
| n->type, |
| offset + type->u.h.data_offset, |
| label)); |
| } else { |
| C(append(proto, GPC_I_PUSH_PTR, |
| offset + type->u.h.data_offset)); |
| C(generate_generator(proto, |
| n->type, |
| 0, |
| label)); |
| } |
| C(append(proto, GPC_I_JUMP, done_label)); |
| } |
| C(append(proto, GPC_I_LABEL, done_label)); |
| if (!tsf_native_choice_type_is_in_place(type)) { |
| 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_STRING_WRITE, offset)); |
| break; |
| case TSF_TK_ANY: |
| C(append(proto, GPC_I_ANY_WRITE, offset)); |
| break; |
| default: |
| tsf_abort("Bad kind code!"); |
| break; |
| } |
| |
| return tsf_true; |
| } |
| |
| gpc_proto_t *tsf_gpc_code_gen_generate_generator(tsf_type_t *type) { |
| gpc_proto_t *proto; |
| |
| if (!tsf_native_type_has_struct_mapping(type)) { |
| tsf_set_error(TSF_E_NO_STRUCT_MAP, NULL); |
| return NULL; |
| } |
| |
| proto=gpc_proto_create(2); |
| if (proto == NULL) { |
| return NULL; |
| } |
| |
| if (!generate_size_calc(proto, type, 0, 0)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!append(proto, GPC_I_MALLOC_BUF)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (tsf_type_is_dynamic(type)) { |
| if (!append(proto, GPC_I_MAKE_OUT_MAP)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| } |
| |
| if (!generate_generator(proto, type, 0, 0)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (tsf_type_is_dynamic(type)) { |
| if (!append(proto, GPC_I_RETURN_ONE_INIT_BUF_WITH_TYPES_FROM_OUT_MAP)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| } else { |
| if (!append(proto, GPC_I_RETURN_ONE_INIT_BUF_WITH_EMPTY_TYPES)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| } |
| |
| return proto; |
| } |
| |
| static tsf_bool_t generate_set_zero_ptr(gpc_proto_t *proto, |
| gpc_cell_t offset) { |
| if (sizeof(void*) == 4) { |
| C(append(proto, GPC_I_SET_L, offset, 0)); |
| } else if (sizeof(void*) == 8) { |
| C(append(proto, GPC_I_SET_L, offset, 0)); |
| C(append(proto, GPC_I_SET_L, offset+4, 0)); |
| } else { |
| tsf_abort("weird pointer size"); |
| } |
| return tsf_true; |
| } |
| |
| static tsf_bool_t generate_set_default(gpc_proto_t *proto, |
| tsf_type_t *dest_type, |
| gpc_cell_t offset) { |
| /* fill in default values */ |
| unsigned i; |
| |
| switch (dest_type->kind_code) { |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_SET_C, offset, 0)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, GPC_I_SET_S, offset, 0)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_SET_L, offset, 0)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_SET_L, offset + 0, 0)); |
| C(append(proto, GPC_I_SET_L, offset + 4, 0)); |
| break; |
| case TSF_TK_FLOAT: { |
| union { |
| float f; |
| uint32_t i; |
| } u; |
| u.f = (float)log(-1.); /* NaN */ |
| C(append(proto, GPC_I_SET_L, offset, u.i)); |
| break; |
| } |
| case TSF_TK_DOUBLE: { |
| union { |
| double d; |
| uint32_t i[2]; |
| } u; |
| u.d = (double)log(-1.); /* NaN */ |
| C(append(proto, GPC_I_SET_L, offset + 0, u.i[0])); |
| C(append(proto, GPC_I_SET_L, offset + 4, u.i[1])); |
| break; |
| } |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_SET_C, offset, 0)); |
| break; |
| case TSF_TK_STRING: |
| C(append(proto, GPC_I_STRING_SETEMPTY, offset)); |
| break; |
| case TSF_TK_ARRAY: |
| switch (dest_type->u.a.element_type->kind_code) { |
| case TSF_TK_VOID: |
| C(append(proto, GPC_I_SET_L, |
| offset + tsf_offsetof(tsf_native_void_array_t, len), |
| 0)); |
| break; |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_SET_L, |
| offset + tsf_offsetof(tsf_native_bitvector_t, num_bits), |
| 0)); |
| C(generate_set_zero_ptr(proto, |
| offset + tsf_offsetof(tsf_native_bitvector_t, |
| bits))); |
| break; |
| default: |
| C(append(proto, GPC_I_SET_L, |
| offset + tsf_offsetof(tsf_native_array_t, len), |
| 0)); |
| C(generate_set_zero_ptr(proto, |
| offset + tsf_offsetof(tsf_native_array_t, |
| data))); |
| break; |
| } |
| break; |
| case TSF_TK_STRUCT: |
| for (i = 0; i < tsf_struct_type_get_num_elements(dest_type); ++i) { |
| tsf_named_type_t *n = tsf_struct_type_get_element(dest_type, i); |
| C(generate_set_default(proto, n->type, |
| offset + n->offset)); |
| } |
| break; |
| case TSF_TK_CHOICE: |
| C(append(proto, GPC_I_SET_L, |
| (gpc_cell_t)(offset + dest_type->u.h.value_offset), |
| (gpc_cell_t)UINT32_MAX)); |
| break; |
| case TSF_TK_ANY: |
| tsf_abort("not implemented"); |
| break; |
| default: |
| tsf_abort("bad kind code"); |
| } |
| |
| return tsf_true; |
| } |
| |
| static tsf_bool_t generate_set_default_copier(gpc_proto_t *proto, |
| tsf_type_t *dest_type, |
| gpc_cell_t offset) { |
| /* this can be optimized... */ |
| |
| C(append(proto, GPC_I_DUP_PTR_2ND)); |
| C(generate_set_default(proto, dest_type, offset)); |
| C(append(proto, GPC_I_POP)); |
| |
| return tsf_true; |
| } |
| |
| static tsf_bool_t generate_parser(gpc_proto_t *proto, |
| tsf_type_t *dest_type, |
| tsf_type_t *src_type, |
| gpc_cell_t offset, |
| gpc_cell_t label, |
| tsf_bool_t do_bounds_check) { |
| uint32_t i, bit = 0, num_bits = 0; |
| gpc_cell_t loop_label, done_label, really_done_label, label_offset; |
| gpc_cell_t *targets; |
| uint32_t static_size; |
| tsf_bool_t result; |
| tsf_bool_t instanceof; |
| |
| static_size = tsf_type_get_static_size(src_type); |
| |
| if (do_bounds_check && static_size != UINT32_MAX) { |
| if (static_size > 0) { |
| C(append(proto, GPC_I_BC, static_size)); |
| } |
| do_bounds_check = tsf_false; |
| } |
| |
| instanceof = tsf_type_instanceof(src_type, dest_type); |
| |
| if (!instanceof) { |
| C(generate_set_default(proto, dest_type, offset)); |
| } |
| |
| if (dest_type->kind_code == TSF_TK_VOID || !instanceof) { |
| /* this is the skip parser. */ |
| |
| tsf_type_t *type = src_type; /* makes things simpler since we |
| * won't refer to dest_type at this |
| * point. */ |
| |
| if (static_size != UINT32_MAX) { |
| if (static_size > 0) { |
| C(append(proto, |
| GPC_I_SKIP, |
| (gpc_cell_t)static_size)); |
| } |
| return tsf_true; |
| } |
| |
| /* interesting observation: from here on, do_bounds_check must be true. |
| * because if do_bounds_check was false, then that means that a bounds |
| * check was possible, which means in turn that our size is statically |
| * known. */ |
| tsf_assert(do_bounds_check); |
| |
| switch (type->kind_code) { |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_TSF_INTEGER_SKIP)); |
| break; |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_TSF_LONG_SKIP)); |
| break; |
| case TSF_TK_STRUCT: |
| 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) { |
| num_bits++; |
| continue; |
| } |
| C(generate_parser(proto, |
| tsf_type_create(TSF_TK_VOID), |
| n->type, |
| 0, |
| label, |
| tsf_true)); |
| } |
| if (num_bits) { |
| C(append(proto, |
| GPC_I_SKIP, |
| (gpc_cell_t)((num_bits + 7) >> 3))); |
| } |
| break; |
| case TSF_TK_ARRAY: |
| if (type->u.a.element_type->kind_code == TSF_TK_VOID) { |
| C(append(proto, GPC_I_ARRAY_LEN_SKIP)); |
| } else if (type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| C(append(proto, GPC_I_BITVECTOR_SKIP)); |
| } else { |
| static_size = |
| tsf_type_get_static_size(type->u.a.element_type); |
| if (static_size == UINT32_MAX) { |
| C(append(proto, GPC_I_ARRAY_LEN_READ_LOCAL)); |
| |
| loop_label = label++; |
| done_label = label++; |
| |
| C(append(proto, GPC_I_ZEROJUMP, done_label)); |
| C(append(proto, GPC_I_LABEL, loop_label)); |
| C(generate_parser(proto, |
| tsf_type_create(TSF_TK_VOID), |
| type->u.a.element_type, |
| 0, |
| label, |
| tsf_true)); |
| C(append(proto, GPC_I_DECCOMPJUMP, loop_label)); |
| C(append(proto, GPC_I_LABEL, done_label)); |
| C(append(proto, GPC_I_POP)); |
| } else { |
| C(append(proto, |
| GPC_I_ARRAY_SKIP, |
| (gpc_cell_t)static_size)); |
| } |
| } |
| break; |
| case TSF_TK_CHOICE: |
| tsf_assert(tsf_choice_type_has_non_void(type) || |
| (tsf_choice_type_get_num_elements(type) >= 256 && |
| !type->u.h.choice_as_full_word)); |
| |
| if (tsf_choice_type_get_num_elements(type) >= 256) { |
| if (type->u.h.choice_as_full_word) { |
| C(append(proto, GPC_I_BC, 4)); |
| C(append(proto, GPC_I_READL)); |
| } else { |
| if (tsf_choice_type_has_non_void(type)) { |
| C(append(proto, GPC_I_TSF_UNSIGNED_READ_SUB1)); |
| } else { |
| C(append(proto, GPC_I_TSF_UNSIGNED_SKIP)); |
| } |
| } |
| } else { |
| C(append(proto, GPC_I_BC, 1)); |
| C(append(proto, GPC_I_READC_TO_CHOICE)); |
| } |
| |
| if (tsf_choice_type_has_non_void(type)) { |
| label_offset = label; |
| label += tsf_choice_type_get_num_elements(type); |
| 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_local( |
| proto, |
| tsf_choice_type_get_num_elements(type), |
| targets); |
| free(targets); |
| if (!result) { |
| return tsf_false; |
| } |
| |
| /* for unknown (default) values */ |
| C(append(proto, GPC_I_JUMP, done_label)); |
| |
| 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)); |
| C(generate_parser(proto, |
| tsf_type_create(TSF_TK_VOID), |
| n->type, |
| 0, |
| label, |
| tsf_true)); |
| C(append(proto, GPC_I_JUMP, done_label)); |
| } |
| C(append(proto, GPC_I_LABEL, done_label)); |
| } |
| break; |
| case TSF_TK_STRING: |
| C(append(proto, GPC_I_STRING_SKIP)); |
| break; |
| case TSF_TK_ANY: |
| C(append(proto, GPC_I_ANY_SKIP)); |
| break; |
| default: |
| tsf_abort("There appears to be a kind code that we don't " |
| "know about"); |
| break; |
| } |
| |
| return tsf_true; |
| } |
| |
| switch (src_type->kind_code) { |
| case TSF_TK_VOID: |
| break; |
| case TSF_TK_INT8: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHC_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_S_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_L_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_LL_E_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_F_E_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_D_E_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT8: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHC_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_S_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_L_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_LL_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_F_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHC_TO_D_Z_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT16: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_C_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHS_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_L_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_LL_E_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_F_E_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_D_E_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT16: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_C_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHS_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_L_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_LL_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_F_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHS_TO_D_Z_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT32: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_C_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_S_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHL_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_LL_E_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_F_E_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_D_E_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT32: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_C_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_S_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHL_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_LL_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_F_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHL_TO_D_Z_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT64: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_C_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_S_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_L_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHLL_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_F_E_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_D_E_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT64: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_C_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_S_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_L_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHLL_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_F_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHLL_TO_D_Z_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_FLOAT: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_C_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_C_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_S_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_S_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_L_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_L_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_LL_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_LL_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHF_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHF_TO_D_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_DOUBLE: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_BIT_INCSRC, offset)); |
| break; |
| case TSF_TK_INT8: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_C_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_C_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_INT16: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_S_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT16: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_S_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_L_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT32: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_L_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_LL_E_INCSRC, offset)); |
| break; |
| case TSF_TK_UINT64: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_LL_Z_INCSRC, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_COPY_NTOHD_TO_F_INCSRC, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_COPY_NTOHD_INCSRC, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INTEGER: |
| tsf_assert(do_bounds_check); |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_TSF_INTEGER_READ_TO_BIT, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_TSF_INTEGER_READ_TO_C, offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, GPC_I_TSF_INTEGER_READ_TO_S, offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_TSF_INTEGER_READ, offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_TSF_INTEGER_READ_TO_LL, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_TSF_INTEGER_READ_TO_F, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_TSF_INTEGER_READ_TO_D, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_LONG: |
| tsf_assert(do_bounds_check); |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_TSF_LONG_READ_TO_BIT, offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, GPC_I_TSF_LONG_READ_TO_C, offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, GPC_I_TSF_LONG_READ_TO_S, offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_TSF_LONG_READ_TO_L, offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_TSF_LONG_READ, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_TSF_LONG_READ_TO_F, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_TSF_LONG_READ_TO_D, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_BIT: |
| switch (dest_type->kind_code) { |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| case TSF_TK_BIT: |
| C(append(proto, GPC_I_BIT_READ, offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, GPC_I_BIT_READ_TO_S, offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, GPC_I_BIT_READ_TO_L, offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, GPC_I_BIT_READ_TO_LL, offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, GPC_I_BIT_READ_TO_F, offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, GPC_I_BIT_READ_TO_D, offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_STRUCT: |
| if (dest_type->u.s.constructor != NULL) { |
| C(append(proto, GPC_I_CALL, |
| offset, |
| dest_type->u.s.constructor)); |
| } |
| if (dest_type->u.s.pre_destructor != NULL) { |
| C(append(proto, GPC_I_ADD_CBACK, |
| offset, |
| dest_type->u.s.pre_destructor)); |
| } |
| |
| for (i = 0; i < tsf_struct_type_get_num_elements(dest_type); ++i) { |
| tsf_named_type_t *dn = tsf_struct_type_get_element(dest_type, i); |
| if (tsf_struct_type_find_node(src_type, dn->name) == NULL) { |
| C(generate_set_default(proto, dn->type, offset + dn->offset)); |
| } |
| } |
| for (i = 0; i < tsf_struct_type_get_num_elements(src_type); ++i) { |
| tsf_named_type_t *sn = tsf_struct_type_get_element(src_type, i); |
| tsf_named_type_t *dn; |
| if (sn->type->kind_code == TSF_TK_BIT) { |
| num_bits++; |
| continue; |
| } |
| dn = tsf_struct_type_find_node(dest_type, sn->name); |
| if (dn == NULL) { |
| /* skip */ |
| C(generate_parser(proto, |
| tsf_type_create(TSF_TK_VOID), |
| sn->type, |
| 0, |
| label, |
| do_bounds_check)); |
| } else { |
| /* read it */ |
| C(generate_parser(proto, |
| dn->type, |
| sn->type, |
| offset + dn->offset, |
| label, |
| do_bounds_check)); |
| } |
| } |
| |
| if (num_bits) { |
| if (do_bounds_check) { |
| C(append(proto, |
| GPC_I_BC, |
| (gpc_cell_t)((num_bits + 7) >> 3))); |
| } |
| |
| for (i = 0; i < tsf_struct_type_get_num_elements(src_type); ++i) { |
| tsf_named_type_t *sn = |
| tsf_struct_type_get_element(src_type, i); |
| tsf_named_type_t *dn; |
| if (sn->type->kind_code != TSF_TK_BIT) { |
| continue; |
| } |
| dn = tsf_struct_type_find_node(dest_type, sn->name); |
| if (dn != NULL) { |
| switch (dn->type->kind_code) { |
| case TSF_TK_VOID: |
| break; |
| case TSF_TK_BIT: |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_BIT_MASK_READ, |
| bit, |
| offset + dn->offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_BIT_MASK_READ_TO_S, |
| bit, |
| offset + dn->offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_BIT_MASK_READ_TO_L, |
| bit, |
| offset + dn->offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_BIT_MASK_READ_TO_LL, |
| bit, |
| offset + dn->offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_BIT_MASK_READ_TO_F, |
| bit, |
| offset + dn->offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_BIT_MASK_READ_TO_D, |
| bit, |
| offset + dn->offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| } |
| ++bit; |
| if (bit == 8) { |
| bit = 0; |
| C(append(proto, GPC_I_SKIP, 1)); |
| } |
| } |
| if (bit) { |
| C(append(proto, GPC_I_SKIP, 1)); |
| } |
| } |
| break; |
| case TSF_TK_ARRAY: |
| if (dest_type->u.a.element_type->kind_code == TSF_TK_VOID) { |
| C(append(proto, |
| GPC_I_ARRAY_LEN_READ_FIELD, |
| offset + tsf_offsetof(tsf_native_void_array_t, |
| len))); |
| |
| if (src_type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| C(append(proto, |
| GPC_I_BITVECTOR_BC_AND_SKIP_FIELD, |
| offset + tsf_offsetof(tsf_native_void_array_t, |
| len))); |
| } else if (src_type->u.a.element_type->kind_code |
| == TSF_TK_VOID) { |
| /* nothing to do */ |
| } else { |
| static_size = |
| tsf_type_get_static_size(src_type->u.a.element_type); |
| if (static_size == UINT32_MAX) { |
| loop_label = label++; |
| done_label = label++; |
| |
| C(append(proto, |
| GPC_I_PUSH_VAL, |
| offset + tsf_offsetof(tsf_native_void_array_t, |
| len))); |
| |
| C(append(proto, GPC_I_ZEROJUMP, done_label)); |
| C(append(proto, GPC_I_LABEL, loop_label)); |
| C(generate_parser(proto, |
| tsf_type_create(TSF_TK_VOID), |
| src_type->u.a.element_type, |
| 0, |
| label, |
| tsf_true)); |
| C(append(proto, GPC_I_DECCOMPJUMP, loop_label)); |
| C(append(proto, GPC_I_LABEL, done_label)); |
| |
| C(append(proto, GPC_I_POP)); |
| } else { |
| C(append(proto, |
| GPC_I_ARRAY_BC_AND_SKIP_FIELD, |
| offset + tsf_offsetof(tsf_native_void_array_t, |
| len), |
| static_size)); |
| } |
| } |
| } else if (dest_type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| switch (src_type->u.a.element_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ, |
| offset)); |
| break; |
| case TSF_TK_UINT8: |
| case TSF_TK_INT8: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_C, |
| offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_S, |
| offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_L, |
| offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_LL, |
| offset)); |
| break; |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_TSF_INTEGER_ARRAY, |
| offset)); |
| break; |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_TSF_LONG_ARRAY, |
| offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_F, |
| offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_FROM_D, |
| offset)); |
| break; |
| default: |
| tsf_abort("odd case"); |
| break; |
| } |
| } else if (src_type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| switch (dest_type->u.a.element_type->kind_code) { |
| case TSF_TK_UINT8: |
| case TSF_TK_INT8: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_TO_C, |
| offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_TO_S, |
| offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_TO_L, |
| offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_TO_LL, |
| offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_TO_F, |
| offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_BITVECTOR_READ_TO_D, |
| offset)); |
| break; |
| default: |
| tsf_abort("odd case"); |
| break; |
| } |
| } else if (src_type->u.a.element_type->kind_code |
| == dest_type->u.a.element_type->kind_code && |
| (src_type->u.a.element_type->kind_code == TSF_TK_UINT8 || |
| src_type->u.a.element_type->kind_code == TSF_TK_INT8 |
| #ifndef NEED_INT_CONVERSION |
| || (tsf_type_kind_is_int(src_type->u.a.element_type->kind_code) |
| && src_type->u.a.element_type->kind_code != TSF_TK_INTEGER |
| && src_type->u.a.element_type->kind_code != TSF_TK_LONG) |
| #endif |
| #ifndef NEED_FLOAT_CONVERSION |
| || tsf_type_kind_is_float(src_type->u.a.element_type->kind_code) |
| #endif |
| )) { |
| C(append(proto, |
| GPC_I_BYTE_ARRAY_READ, |
| offset, |
| tsf_type_get_static_size(src_type->u.a.element_type))); |
| } else { |
| C(append(proto, |
| GPC_I_ARRAY_LEN_READ_FIELD, |
| offset + tsf_offsetof(tsf_native_array_t, len))); |
| |
| static_size = tsf_type_get_static_size(src_type->u.a.element_type); |
| if (static_size != UINT32_MAX) { |
| C(append(proto, |
| GPC_I_ARRAY_BC_FIELD, |
| offset + tsf_offsetof(tsf_native_array_t, len), |
| static_size)); |
| } |
| |
| C(append(proto, |
| GPC_I_ALLOC_ARRAY, |
| offset, |
| tsf_native_type_get_size(dest_type->u.a.element_type))); |
| |
| loop_label = label++; |
| done_label = label++; |
| |
| C(append(proto, |
| GPC_I_REPUSH_MULADD_PTR, |
| offset + tsf_offsetof(tsf_native_array_t,len), |
| tsf_native_type_get_size(dest_type->u.a.element_type))); |
| C(append(proto, |
| GPC_I_COMPFAILJUMP, |
| done_label)); |
| C(append(proto, GPC_I_LABEL, loop_label)); |
| C(generate_parser(proto, |
| dest_type->u.a.element_type, |
| src_type->u.a.element_type, |
| 0, |
| label, |
| static_size == UINT32_MAX)); |
| C(append(proto, |
| GPC_I_ADDCOMPJUMP, |
| tsf_native_type_get_size(dest_type->u.a.element_type), |
| loop_label)); |
| C(append(proto, GPC_I_LABEL, done_label)); |
| C(append(proto, GPC_I_TWO_POP)); |
| } |
| break; |
| case TSF_TK_CHOICE: |
| if (tsf_choice_type_get_num_elements(src_type) >= 256) { |
| if (src_type->u.h.choice_as_full_word) { |
| if (do_bounds_check) { |
| C(append(proto, GPC_I_BC, 4)); |
| } |
| C(append(proto, GPC_I_READL)); |
| } else { |
| C(append(proto, GPC_I_TSF_UNSIGNED_READ_SUB1)); |
| } |
| } else { |
| if (do_bounds_check) { |
| C(append(proto, GPC_I_BC, 1)); |
| } |
| C(append(proto, GPC_I_READC_TO_CHOICE)); |
| } |
| |
| if (tsf_choice_type_has_non_void(src_type)) { |
| /* use tablejump */ |
| label_offset = label; |
| label += tsf_choice_type_get_num_elements(src_type); |
| done_label = label++; |
| really_done_label = label++; |
| targets=malloc(sizeof(gpc_cell_t) * |
| tsf_choice_type_get_num_elements(src_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(src_type); ++i) { |
| targets[i] = label_offset + i; |
| } |
| result=append_tablejump_local(proto, |
| tsf_choice_type_get_num_elements(src_type), |
| targets); |
| free(targets); |
| if (!result) { |
| return tsf_false; |
| } |
| C(append(proto, |
| GPC_I_SET_L, |
| (gpc_cell_t)(offset + dest_type->u.h.value_offset), |
| (gpc_cell_t)UINT32_MAX)); |
| C(append(proto, GPC_I_JUMP, really_done_label)); |
| for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) { |
| tsf_named_type_t *sn = |
| tsf_choice_type_get_element(src_type, i); |
| tsf_named_type_t *dn = |
| tsf_choice_type_find_node(dest_type, sn->name); |
| C(append(proto, GPC_I_LABEL, label_offset + i)); |
| if (dn == NULL) { |
| C(append(proto, |
| GPC_I_SET_L, |
| (gpc_cell_t)offset + dest_type->u.h.value_offset, |
| (gpc_cell_t)UINT32_MAX)); |
| C(generate_parser(proto, |
| tsf_type_create(TSF_TK_VOID), |
| sn->type, |
| 0, |
| label, |
| tsf_true)); |
| C(append(proto, GPC_I_JUMP, really_done_label)); |
| } else { |
| C(append(proto, |
| GPC_I_SET_L, |
| (gpc_cell_t)offset + dest_type->u.h.value_offset, |
| (gpc_cell_t)dn->index)); |
| if (tsf_native_choice_type_is_in_place(dest_type)) { |
| C(generate_parser(proto, |
| dn->type, |
| sn->type, |
| offset + dest_type->u.h.data_offset, |
| label, |
| tsf_true)); |
| } else { |
| C(append(proto, |
| GPC_I_ALLOC, |
| tsf_native_type_get_size(dn->type))); |
| C(append(proto, |
| GPC_I_STORE_PTR, |
| offset + dest_type->u.h.data_offset)); |
| C(generate_parser(proto, |
| dn->type, |
| sn->type, |
| 0, |
| label, |
| tsf_true)); |
| } |
| C(append(proto, GPC_I_JUMP, done_label)); |
| } |
| } |
| C(append(proto, GPC_I_LABEL, done_label)); |
| if (!tsf_native_choice_type_is_in_place(dest_type)) { |
| C(append(proto, GPC_I_POP)); |
| } |
| C(append(proto, GPC_I_LABEL, really_done_label)); |
| } else if (tsf_choice_type_uses_same_indices(src_type, |
| dest_type)) { |
| /* use checkchoice and store */ |
| C(append(proto, |
| GPC_I_CHECKCHOICE, |
| tsf_choice_type_get_num_elements(src_type))); |
| C(append(proto, |
| GPC_I_STORE_VAL, |
| offset + dest_type->u.h.value_offset)); |
| C(append(proto, GPC_I_POP)); |
| } else { |
| /* use tableset_local_to_field */ |
| targets=malloc(sizeof(gpc_cell_t) * |
| tsf_choice_type_get_num_elements(src_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(src_type); ++i) { |
| tsf_named_type_t *sn = |
| tsf_choice_type_get_element(src_type, i); |
| tsf_named_type_t *dn = |
| tsf_choice_type_find_node(dest_type, sn->name); |
| if (dn == NULL) { |
| targets[i] = UINT32_MAX; |
| } else { |
| targets[i] = dn->index; |
| } |
| } |
| result = append_tableset_local_to_field( |
| proto, |
| offset + dest_type->u.h.value_offset, |
| tsf_choice_type_get_num_elements(src_type), |
| targets); |
| free(targets); |
| if (!result) { |
| return tsf_false; |
| } |
| } |
| break; |
| case TSF_TK_STRING: |
| C(append(proto, GPC_I_STRING_READ, offset)); |
| break; |
| case TSF_TK_ANY: |
| C(append(proto, GPC_I_ANY_READ, offset)); |
| break; |
| default: |
| tsf_abort("Unknown type"); |
| break; |
| } |
| |
| return tsf_true; |
| } |
| |
| gpc_proto_t *tsf_gpc_code_gen_generate_parser(tsf_type_t *dest_type, |
| tsf_type_t *src_type) { |
| gpc_proto_t *proto; |
| |
| if (!tsf_native_type_has_struct_mapping(dest_type)) { |
| tsf_set_error(TSF_E_NO_STRUCT_MAP, NULL); |
| return NULL; |
| } |
| |
| if (!tsf_type_instanceof(src_type, dest_type)) { |
| tsf_set_error(TSF_E_TYPE_MISMATCH, NULL); |
| return NULL; |
| } |
| |
| proto=gpc_proto_create(2); |
| if (proto==NULL) { |
| return NULL; |
| } |
| |
| if (!append(proto, GPC_I_POP_BUF)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!generate_parser(proto, |
| dest_type, |
| src_type, |
| 0, |
| 0, |
| tsf_true)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!append(proto, GPC_I_RETURN_ONE)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| return proto; |
| } |
| |
| static tsf_bool_t generate_converter(gpc_proto_t *proto, |
| tsf_type_t *dest_type, |
| tsf_type_t *src_type, |
| gpc_cell_t dest_offset, |
| gpc_cell_t src_offset, |
| gpc_cell_t label) { |
| uint32_t i; |
| gpc_cell_t done_label,really_done_label; |
| gpc_cell_t loop_label; |
| gpc_cell_t label_offset; |
| gpc_cell_t *targets; |
| tsf_bool_t result; |
| |
| if (dest_type->kind_code == TSF_TK_VOID) { |
| return tsf_true; |
| } |
| |
| if (!tsf_type_instanceof(src_type, dest_type)) { |
| C(generate_set_default_copier(proto, dest_type, dest_offset)); |
| } |
| |
| /* reason why we don't memcpy primitives: if we see a primitive at |
| this point, then it is just one word - so a primitive copy |
| operation will be faster than memcpy. |
| |
| interestingly, if we see a struct that contains exactly one |
| primitive, we will still use memcpy (unless it is a byte). this |
| is not optimal, but oh well. */ |
| if (!tsf_type_kind_is_primitive(tsf_type_get_kind_code(src_type)) && |
| tsf_native_type_can_blit(dest_type,src_type)) { |
| switch (tsf_native_type_get_size(src_type)) { |
| case 0: |
| break; |
| case 1: |
| C(append(proto, |
| GPC_I_COPY_C, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| C(append(proto, |
| GPC_I_MEMCPY, |
| dest_offset, |
| src_offset, |
| tsf_native_type_get_size(src_type))); |
| break; |
| } |
| return tsf_true; |
| } |
| |
| switch (src_type->kind_code) { |
| case TSF_TK_BIT: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| tsf_abort("bit-to-bit copies should have been handled elsewhere"); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_BIT_TO_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_BIT_TO_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_BIT_TO_LL, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_BIT_TO_F, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_BIT_TO_D, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT8: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_C_TO_S_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_C_TO_L_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_C_TO_LL_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_C_TO_F_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_C_TO_D_E, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT8: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_C_TO_S_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_C_TO_L_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_C_TO_LL_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_C_TO_F_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_C_TO_D_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT16: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_S_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_S_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_S_TO_L_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_S_TO_LL_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_S_TO_F_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_S_TO_D_E, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT16: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_S_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_S_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_S_TO_L_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_S_TO_LL_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_S_TO_F_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_S_TO_D_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_L_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_L_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_L_TO_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_L_TO_LL_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_L_TO_F_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_L_TO_D_E, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT32: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_L_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_L_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_L_TO_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_L_TO_LL_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_L_TO_F_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_L_TO_D_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_LL, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_F_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_D_E, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_UINT64: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_UINT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_UINT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_LL, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_F_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_LL_TO_D_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_FLOAT: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_F_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_F_TO_C_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| C(append(proto, |
| GPC_I_COPY_F_TO_C_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_F_TO_S_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| C(append(proto, |
| GPC_I_COPY_F_TO_S_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT32: |
| C(append(proto, |
| GPC_I_COPY_F_TO_L_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_F_TO_L_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT64: |
| C(append(proto, |
| GPC_I_COPY_F_TO_LL_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_F_TO_LL_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_F, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_F_TO_D, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_DOUBLE: |
| switch (dest_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_D_TO_BIT, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT8: |
| C(append(proto, |
| GPC_I_COPY_D_TO_C_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT8: |
| C(append(proto, |
| GPC_I_COPY_D_TO_C_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT16: |
| C(append(proto, |
| GPC_I_COPY_D_TO_S_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT16: |
| C(append(proto, |
| GPC_I_COPY_D_TO_S_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT32: |
| C(append(proto, |
| GPC_I_COPY_D_TO_L_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_D_TO_L_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT64: |
| C(append(proto, |
| GPC_I_COPY_D_TO_LL_Z, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_D_TO_LL_E, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_D_TO_F, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_D, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad src_type/dest_type combination; " |
| "should have been caught by " |
| "tsf_type_instanceof()"); |
| break; |
| } |
| break; |
| case TSF_TK_STRUCT: |
| if (dest_type->u.s.constructor != NULL || |
| dest_type->u.s.pre_destructor != NULL) { |
| /* This could be optimized by adding I_CALL_2ND and I_ADD_CBACK_2ND. I don't think |
| it's worth it. */ |
| |
| C(append(proto, GPC_I_DUP_PTR_2ND)); |
| if (dest_type->u.s.constructor != NULL) { |
| C(append(proto, GPC_I_CALL, |
| dest_offset, |
| dest_type->u.s.constructor)); |
| } |
| if (dest_type->u.s.pre_destructor != NULL) { |
| C(append(proto, GPC_I_ADD_CBACK, |
| dest_offset, |
| dest_type->u.s.pre_destructor)); |
| } |
| C(append(proto, GPC_I_POP)); |
| } |
| |
| for (i = 0; i < tsf_struct_type_get_num_elements(dest_type); ++i) { |
| tsf_named_type_t *n = |
| tsf_struct_type_get_element(dest_type, i); |
| |
| tsf_named_type_t *n2 = |
| tsf_struct_type_find_node(src_type, n->name); |
| |
| if (n2 == NULL) { |
| C(generate_set_default_copier( |
| proto, n->type, dest_offset + n->offset)); |
| } else { |
| C(generate_converter(proto, |
| n->type, |
| n2->type, |
| dest_offset + n->offset, |
| src_offset + n2->offset, |
| label)); |
| } |
| } |
| break; |
| case TSF_TK_ARRAY: |
| if (dest_type->u.a.element_type->kind_code == TSF_TK_VOID) { |
| C(append(proto, |
| GPC_I_COPY_L, |
| (gpc_cell_t)(dest_offset + |
| tsf_offsetof(tsf_native_void_array_t, len)), |
| (gpc_cell_t)(src_offset + |
| src_type->u.a.element_type->kind_code == TSF_TK_VOID |
| ? tsf_offsetof(tsf_native_void_array_t, len) |
| : (src_type->u.a.element_type->kind_code == TSF_TK_BIT |
| ? tsf_offsetof(tsf_native_bitvector_t, num_bits) |
| : tsf_offsetof(tsf_native_array_t, len))))); |
| } else if (dest_type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| switch (src_type->u.a.element_type->kind_code) { |
| case TSF_TK_BIT: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT8: |
| case TSF_TK_INT8: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_FROM_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_FROM_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_FROM_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_FROM_LL, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_FROM_F, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_FROM_D, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("case missed"); |
| break; |
| } |
| } else if (src_type->u.a.element_type->kind_code == TSF_TK_BIT) { |
| switch (dest_type->u.a.element_type->kind_code) { |
| case TSF_TK_UINT8: |
| case TSF_TK_INT8: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_TO_C, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT16: |
| case TSF_TK_INT16: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_TO_S, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT32: |
| case TSF_TK_INT32: |
| case TSF_TK_INTEGER: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_TO_L, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_UINT64: |
| case TSF_TK_INT64: |
| case TSF_TK_LONG: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_TO_LL, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_FLOAT: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_TO_F, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_DOUBLE: |
| C(append(proto, |
| GPC_I_COPY_BITVECTOR_TO_D, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("case missed"); |
| } |
| } else if (tsf_native_type_can_blit(dest_type->u.a.element_type, |
| src_type->u.a.element_type) && |
| tsf_native_type_get_size(dest_type->u.a.element_type) == |
| tsf_native_type_get_size(src_type->u.a.element_type)) { |
| C(append(proto, |
| GPC_I_COPY_ARRAY, |
| dest_offset, |
| src_offset, |
| tsf_native_type_get_size(dest_type->u.a.element_type))); |
| } else { |
| loop_label = label++; |
| done_label = label++; |
| |
| C(append(proto, |
| GPC_I_COPY_L, |
| dest_offset + tsf_offsetof(tsf_native_array_t, len), |
| src_offset + tsf_offsetof(tsf_native_array_t, len))); |
| C(append(proto, |
| GPC_I_ALLOC_ARRAY_2ND, |
| dest_offset, |
| tsf_native_type_get_size(dest_type->u.a.element_type))); |
| C(append(proto, |
| GPC_I_REPUSH_MULADD_PTR_2ND, |
| dest_offset + tsf_offsetof(tsf_native_array_t, len), |
| tsf_native_type_get_size(dest_type->u.a.element_type))); |
| C(append(proto, |
| GPC_I_PUSH_PTR_3RD, |
| src_offset + tsf_offsetof(tsf_native_array_t, data))); |
| C(append(proto, |
| GPC_I_COMPFAILJUMP_2ND, |
| done_label)); |
| C(append(proto,GPC_I_LABEL, loop_label)); |
| C(generate_converter(proto, |
| dest_type->u.a.element_type, |
| src_type->u.a.element_type, |
| 0, |
| 0, |
| label)); |
| C(append(proto, |
| GPC_I_TWO_ADDCOMPJUMP, |
| tsf_native_type_get_size(dest_type->u.a.element_type), |
| tsf_native_type_get_size(src_type->u.a.element_type), |
| loop_label)); |
| C(append(proto, GPC_I_LABEL, done_label)); |
| C(append(proto, GPC_I_THREE_POP)); |
| } |
| break; |
| case TSF_TK_CHOICE: |
| targets=malloc(sizeof(gpc_cell_t) * |
| tsf_choice_type_get_num_elements(src_type)); |
| if (targets == NULL) { |
| tsf_set_errno("Could not malloc array of " |
| "gpc_cell_t"); |
| return tsf_false; |
| } |
| if (tsf_choice_type_has_non_void(src_type)) { |
| label_offset = label; |
| label += tsf_choice_type_get_num_elements(src_type); |
| done_label = label++; |
| really_done_label = label++; |
| for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) { |
| targets[i] = label_offset + i; |
| } |
| result = append_tablejump_field( |
| proto, |
| src_offset + src_type->u.h.value_offset, |
| tsf_choice_type_get_num_elements(src_type), |
| targets); |
| free(targets); |
| if (!result) { |
| return tsf_false; |
| } |
| C(append(proto, |
| GPC_I_SET_2ND_L, |
| (gpc_cell_t)(dest_offset + dest_type->u.h.value_offset), |
| (gpc_cell_t)UINT32_MAX)); |
| C(append(proto, GPC_I_JUMP, really_done_label)); |
| for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) { |
| tsf_named_type_t *sn = |
| tsf_choice_type_get_element(src_type, i); |
| tsf_named_type_t *dn = |
| tsf_choice_type_find_node(dest_type, sn->name); |
| C(append(proto, GPC_I_LABEL, label_offset + i)); |
| if (dn == NULL) { |
| C(append(proto, |
| GPC_I_SET_2ND_L, |
| (gpc_cell_t)(dest_offset + dest_type->u.h.value_offset), |
| (gpc_cell_t)UINT32_MAX)); |
| C(append(proto, GPC_I_JUMP, really_done_label)); |
| } else { |
| C(append(proto, |
| GPC_I_SET_2ND_L, |
| (gpc_cell_t)(dest_offset + dest_type->u.h.value_offset), |
| (gpc_cell_t)dn->index)); |
| if (!tsf_native_choice_type_is_in_place(src_type) || |
| !tsf_native_choice_type_is_in_place(dest_type)) { |
| uint32_t src_off = 0; |
| uint32_t dest_off = 0; |
| if (tsf_native_choice_type_is_in_place(dest_type)) { |
| C(append(proto, GPC_I_DUP_PTR_2ND)); |
| dest_off = dest_offset + |
| dest_type->u.h.data_offset; |
| } else { |
| /* must alloc */ |
| C(append(proto, GPC_I_ALLOC, |
| tsf_native_type_get_size(dn->type))); |
| C(append(proto, GPC_I_STORE_PTR_2ND, |
| dest_offset + |
| dest_type->u.h.data_offset)); |
| } |
| if (tsf_native_choice_type_is_in_place(src_type)) { |
| C(append(proto, GPC_I_DUP_PTR_2ND)); |
| src_off = src_offset + |
| src_type->u.h.data_offset; |
| } else { |
| /* just load */ |
| C(append(proto, GPC_I_PUSH_PTR_2ND, |
| src_offset + |
| src_type->u.h.data_offset)); |
| } |
| C(generate_converter(proto, |
| dn->type, |
| sn->type, |
| dest_off, |
| src_off, |
| label)); |
| C(append(proto, GPC_I_JUMP, done_label)); |
| } else { |
| C(generate_converter(proto, |
| dn->type, |
| sn->type, |
| dest_offset + |
| dest_type->u.h.data_offset, |
| src_offset + |
| src_type->u.h.data_offset, |
| label)); |
| C(append(proto, GPC_I_JUMP, really_done_label)); |
| } |
| } |
| } |
| C(append(proto, GPC_I_LABEL, done_label)); |
| if (!tsf_native_choice_type_is_in_place(src_type) || |
| !tsf_native_choice_type_is_in_place(dest_type)) { |
| C(append(proto, GPC_I_TWO_POP)); |
| } |
| C(append(proto, GPC_I_LABEL, really_done_label)); |
| } else { |
| for (i = 0; i < tsf_choice_type_get_num_elements(src_type); ++i) { |
| tsf_named_type_t *sn = |
| tsf_choice_type_get_element(src_type, i); |
| tsf_named_type_t *dn = |
| tsf_choice_type_find_node(dest_type, sn->name); |
| if (dn == NULL) { |
| targets[i] = UINT32_MAX; |
| } else { |
| targets[i] = dn->index; |
| } |
| } |
| result = append_tableset_field_to_field( |
| proto, |
| dest_offset + dest_type->u.h.value_offset, |
| src_offset + src_type->u.h.value_offset, |
| tsf_choice_type_get_num_elements(src_type), |
| targets); |
| free(targets); |
| if (!result) { |
| return tsf_false; |
| } |
| } |
| break; |
| case TSF_TK_STRING: |
| C(append(proto, |
| GPC_I_STRING_COPY, |
| dest_offset, |
| src_offset)); |
| break; |
| case TSF_TK_ANY: |
| C(append(proto, |
| GPC_I_ANY_COPY, |
| dest_offset, |
| src_offset)); |
| break; |
| default: |
| tsf_abort("Bad type."); |
| break; |
| } |
| |
| return tsf_true; |
| } |
| |
| gpc_proto_t *tsf_gpc_code_gen_generate_converter(tsf_type_t *dest_type, |
| tsf_type_t *src_type) { |
| gpc_proto_t *proto; |
| |
| if (!tsf_native_type_has_struct_mapping(dest_type)) { |
| tsf_set_error(TSF_E_NO_STRUCT_MAP, |
| "Destination lacks a structure mapping"); |
| return NULL; |
| } |
| |
| if (!tsf_native_type_has_struct_mapping(src_type)) { |
| tsf_set_error(TSF_E_NO_STRUCT_MAP, |
| "Source lacks a structure mapping"); |
| return NULL; |
| } |
| |
| if (!tsf_type_instanceof(src_type, dest_type)) { |
| tsf_set_error(TSF_E_TYPE_MISMATCH, NULL); |
| return NULL; |
| } |
| |
| proto = gpc_proto_create(2); |
| if (proto == NULL) { |
| return NULL; |
| } |
| |
| /* FIXME: The caller should allocate the region for us. */ |
| if (!append(proto, |
| GPC_I_ALLOC_ROOT_MAYBE_2ND, |
| tsf_native_type_get_size(dest_type))) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!generate_converter(proto, |
| dest_type, |
| src_type, |
| 0, |
| 0, |
| 0)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!append(proto, GPC_I_POP)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!append(proto, GPC_I_RETURN_TOP_WITH_REGION)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| return proto; |
| } |
| |
| static tsf_bool_t needs_destruction(tsf_type_t *type) { |
| uint32_t i; |
| |
| switch (type->kind_code) { |
| case TSF_TK_STRUCT: |
| if (type->u.s.destructor != NULL) { |
| return tsf_true; |
| } else { |
| if (type->u.s.pre_destructor != NULL) { |
| return tsf_true; |
| } |
| 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; |
| } |
| if (needs_destruction(n->type)) { |
| return tsf_true; |
| } |
| } |
| } |
| 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 { |
| return tsf_true; |
| } |
| break; |
| case TSF_TK_CHOICE: |
| if (tsf_choice_type_has_non_void(type)) { |
| return tsf_true; |
| } |
| break; |
| case TSF_TK_STRING: |
| return tsf_true; |
| case TSF_TK_ANY: |
| return tsf_true; |
| default: |
| /* None of the other types have things that need to be freed. */ |
| break; |
| } |
| |
| return tsf_false; |
| } |
| |
| 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; |
| } |
| |
| gpc_proto_t *tsf_gpc_code_gen_generate_destroyer(tsf_type_t *type) { |
| gpc_proto_t *proto; |
| |
| if (!tsf_native_type_has_struct_mapping(type)) { |
| tsf_set_error(TSF_E_NO_STRUCT_MAP, NULL); |
| return NULL; |
| } |
| |
| proto = gpc_proto_create(1); |
| if (proto == NULL) { |
| return NULL; |
| } |
| |
| if (!generate_destroyer(proto, type, 0, 0)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| if (!append(proto, GPC_I_RETURN_ONE)) { |
| gpc_proto_destroy(proto); |
| return NULL; |
| } |
| |
| return proto; |
| } |
| |
| |