From 40f25fd0d6c690375e94e54168a3646cc587774e Mon Sep 17 00:00:00 2001 From: Alexander Motzkau Date: Mon, 14 Sep 2020 22:44:28 +0200 Subject: [PATCH 1/2] Implemented option to use POSIX timers for DC_LONG_EXEC_TIME POSIX timers allow to have multiple real time timers running. But those timers are an optional feature of POSIX 2001, therefore it is a configurable feature. --- src/autoconf/configure.ac | 46 +++++++++++++++++++++++++++ src/backend.c | 3 ++ src/interpret.c | 66 +++++++++++++++++++++++++++++++++++++-- src/interpret.h | 1 + src/settings/unitopia | 1 + 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/autoconf/configure.ac b/src/autoconf/configure.ac index 50df05a8a..c49d4a858 100644 --- a/src/autoconf/configure.ac +++ b/src/autoconf/configure.ac @@ -255,6 +255,7 @@ AC_MY_ARG_ENABLE(trace-code,yes,,[trace the most recently executed bytecode]) AC_MY_ARG_ENABLE(rxcache_table,yes,,[Cache compiled regular expressions]) AC_MY_ARG_ENABLE(synchronous-heart-beat,yes,,[Do all heart beats at once.]) +AC_MY_ARG_ENABLE(posix-timers,no,,[Use POSIX timers for the execution timer]) AC_MY_ARG_ENABLE(opcprof,no,,[create VM instruction usage statistics]) AC_MY_ARG_ENABLE(verbose-opcprof,no,,[with opcprof: include instruction names]) AC_MY_ARG_ENABLE(debug,yes,,[enable sanity checks]) @@ -533,6 +534,7 @@ AC_CDEF_FROM_ENABLE(trace_code) AC_CDEF_FROM_ENABLE(rxcache_table) AC_CDEF_FROM_ENABLE(synchronous_heart_beat) +AC_UPDATE_VAR(enable_posix_timers) AC_CDEF_FROM_ENABLE(opcprof) AC_CDEF_FROM_ENABLE(verbose_opcprof) AC_CDEF_FROM_ENABLE(debug) @@ -1893,6 +1895,50 @@ if test "x$enable_use_mccp" = "x" || test "x$enable_use_mccp" = "xyes"; then fi fi +# --- Check for POSIX timer --- + +AC_MY_SEARCH_LIB(RT,posix-timers,lp_cv_has_posix_timers,posix,posix_path, +[ + #include + #include + + int init(void) + { + timer_t timerid; + struct sigevent sev; + struct itimerspec its; + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIGPROF; + sev.sigev_value.sival_ptr = &timerid; + if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) + return 1; + + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 500000000; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + + if (timer_settime(timerid, 0, &its, NULL) == -1) + return 2; + + timer_delete(timerid); + return 0; + } +],rt,timer_create,enable_posix_timers) + +if test "$lp_cv_has_posix_timers" = "yes"; then + AC_DEFINE(USE_POSIX_TIMERS, 1, [Use POSIX timers for the execution timer?]) +else + if test "x$enable_posix_timers" = "xyes"; then + echo "POSIX timer not supported - disabling." + AC_NOT_AVAILABLE(posix-timers) + fi + + cdef_posix_timers="#undef" + enable_posix_timers="no" +fi + # --- AC_CACHE_CHECK(if rename handles directories, diff --git a/src/backend.c b/src/backend.c index 85297f15f..95bfe2f36 100644 --- a/src/backend.c +++ b/src/backend.c @@ -647,6 +647,9 @@ void install_signal_handlers() if (sigaction(SIGUSR2, &sa, NULL) == -1) perror("Unable to install signal handler for SIGUSR2"); // Profiling signal handler for the detection of long executions. + if (!init_profiling_timer()) + debug_message("%s Unable to create a POSIX timer for profiling, " + "falling back to ITIMER_PROF\n", time_stamp()); sa.sa_handler = handle_profiling_signal; if (sigaction(SIGPROF, &sa, NULL) == -1) { profiling_timevalue.tv_sec = 0; diff --git a/src/interpret.c b/src/interpret.c index 9b6c9e6b3..2974206f0 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -189,6 +189,7 @@ #include "my-alloca.h" #include +#include #include #include #include @@ -757,6 +758,16 @@ struct timeval profiling_timevalue = {0, 0}; static Bool received_prof_signal = MY_FALSE; +#ifdef USE_POSIX_TIMERS +static timer_t prof_timer; + /* POSIX timer id used for the profiling signal. + */ + +static bool have_prof_timer = false; + /* Is prof_timer a valid timer? + */ +#endif + p_int used_memory_at_eval_start = 0; /* used memory (in bytes) at the beginning of the current execution, * set by mark_start_evaluation() (and v_limited()). @@ -840,6 +851,28 @@ assign_eval_cost_inl(void) void assign_eval_cost(void) { assign_eval_cost_inl(); } +/*-------------------------------------------------------------------------*/ + +bool +init_profiling_timer () +/* Initializes the timer used for long execution signals. + */ +{ +#ifdef USE_POSIX_TIMERS + struct sigevent sev; + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIGPROF; + sev.sigev_value.sival_ptr = NULL; + sev.sigev_value.sival_int = 0; + if (timer_create(CLOCK_REALTIME, &sev, &prof_timer) == -1) + return false; + + have_prof_timer = true; +#endif + return true; +} /* init_profiling_timer() */ + /*-------------------------------------------------------------------------*/ void handle_profiling_signal(int ignored) @@ -860,6 +893,9 @@ mark_start_evaluation (void) { // .it_interval is always zero (no auto-repeat), .it_value will be set later static struct itimerval prof_time_val = { {0,0}, {0,0} }; +#ifdef USE_POSIX_TIMERS + static struct itimerspec prof_ptime_val = { {0,0}, {0,0} }; +#endif total_evalcost = 0; eval_number++; @@ -867,8 +903,24 @@ mark_start_evaluation (void) // start the profiling timer if enabled if (profiling_timevalue.tv_usec || profiling_timevalue.tv_sec) { - prof_time_val.it_value = profiling_timevalue; - setitimer(ITIMER_PROF, &prof_time_val, NULL); +#ifdef USE_POSIX_TIMERS + if (have_prof_timer) + { + prof_ptime_val.it_value.tv_sec = profiling_timevalue.tv_sec; + prof_ptime_val.it_value.tv_nsec = profiling_timevalue.tv_usec * 1000L; + if (timer_settime(prof_timer, 0, &prof_ptime_val, NULL) == -1) + { + debug_message("%s Could not start execution timer: %s\n" + , time_stamp(), strerror(errno)); + have_prof_timer = false; + } + } + if (!have_prof_timer) +#endif + { + prof_time_val.it_value = profiling_timevalue; + setitimer(ITIMER_PROF, &prof_time_val, NULL); + } } if (gettimeofday(&eval_begin, NULL)) @@ -892,10 +944,20 @@ mark_end_evaluation (void) { static struct itimerval prof_time_val = { {0,0}, {0,0} }; +#ifdef USE_POSIX_TIMERS + static struct itimerspec prof_ptime_val = { {0,0}, {0,0} }; +#endif // disable the profiling timer if (profiling_timevalue.tv_usec || profiling_timevalue.tv_sec) + { +#ifdef USE_POSIX_TIMERS + if (have_prof_timer) + timer_settime(prof_timer, 0, &prof_ptime_val, NULL); + else +#endif setitimer(ITIMER_PROF, &prof_time_val, NULL); + } if (total_evalcost == 0) return; diff --git a/src/interpret.h b/src/interpret.h index 228599547..df1c16073 100644 --- a/src/interpret.h +++ b/src/interpret.h @@ -380,6 +380,7 @@ extern void check_a_lot_ref_counts(program_t *search_prog); #endif // signal handler for profiling (SIGPROF) +extern bool init_profiling_timer(); extern void handle_profiling_signal(int ignored); extern Bool set_profiling_time_limit(mp_int limit); extern mp_int get_profiling_time_limit(); diff --git a/src/settings/unitopia b/src/settings/unitopia index bdb9f6a4c..d10e6f6ae 100755 --- a/src/settings/unitopia +++ b/src/settings/unitopia @@ -52,6 +52,7 @@ with_tls_keyfile=no enable_malloc_trace=yes enable_malloc_lpc_trace=yes enable_use_pthreads=no +enable_posix_timers=yes # --- Wizlist --- with_wizlist_file=no From 84a6d044fd476a60276b67c7000f2543a674ff61 Mon Sep 17 00:00:00 2001 From: Alexander Motzkau Date: Tue, 2 Aug 2022 23:55:23 +0200 Subject: [PATCH 2/2] Temporary: Annotate type functions with malloc trace arguments To track some very rare leaks of type objects add malloc trace arguments to the type functions. --- src/prolang.y | 13 +++++++--- src/types.c | 70 +++++++++++++++++++++++++-------------------------- src/types.h | 30 +++++++++++++++------- 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/prolang.y b/src/prolang.y index 29e32f7d7..c18c60cf4 100644 --- a/src/prolang.y +++ b/src/prolang.y @@ -2370,6 +2370,13 @@ get_common_array_type (lpctype_t* t1, lpctype_t* t2) return result; } +static lpctype_t* +get_common_lpc_type (lpctype_t* t1, lpctype_t* t2) + +{ + return get_common_type(t1, t2); +} + static lpctype_t* get_sub_array_type (lpctype_t* t1, lpctype_t* t2) @@ -2546,7 +2553,7 @@ binary_op_types_t types_binary_and_assignment[] = { { &_lpctype_mapping, &_lpctype_mapping, &_lpctype_mapping, NULL , NULL , NULL }, { &_lpctype_mapping, &_lpctype_any_array, &_lpctype_mapping, NULL , NULL , NULL }, { &_lpctype_any_array, &_lpctype_mapping, NULL, &get_first_type , NULL , NULL }, - { &_lpctype_any_array, &_lpctype_any_array, NULL, &get_common_type , NULL , NULL }, + { &_lpctype_any_array, &_lpctype_any_array, NULL, &get_common_lpc_type , NULL , NULL }, { &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL }, { &_lpctype_string, &_lpctype_string, &_lpctype_string, NULL , NULL , NULL }, { &_lpctype_bytes, &_lpctype_bytes, &_lpctype_bytes, NULL , NULL , NULL }, @@ -2596,7 +2603,7 @@ binary_op_types_t types_binary_and[] = { { &_lpctype_mapping, &_lpctype_mapping, &_lpctype_mapping, NULL , NULL , NULL }, { &_lpctype_mapping, &_lpctype_any_array, &_lpctype_mapping, NULL , NULL , NULL }, { &_lpctype_any_array, &_lpctype_mapping, NULL, &get_first_type , NULL , NULL }, - { &_lpctype_any_array, &_lpctype_any_array, NULL, &get_common_type , NULL , NULL }, + { &_lpctype_any_array, &_lpctype_any_array, NULL, &get_common_lpc_type , NULL , NULL }, { &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL }, { &_lpctype_string, &_lpctype_string, &_lpctype_string, NULL , NULL , NULL }, { &_lpctype_bytes, &_lpctype_bytes, &_lpctype_bytes, NULL , NULL , NULL }, @@ -2608,7 +2615,7 @@ binary_op_types_t types_binary_and[] = { * Basically there must be a common type, but ints can be compared with floats also. */ binary_op_types_t types_equality[] = { - { &_lpctype_mixed, &_lpctype_mixed, &_lpctype_int, &get_common_type , NULL , NULL }, + { &_lpctype_mixed, &_lpctype_mixed, &_lpctype_int, &get_common_lpc_type , NULL , NULL }, { &_lpctype_int, &_lpctype_float, &_lpctype_int, NULL , NULL , NULL }, { &_lpctype_float, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL }, { NULL, NULL, NULL, NULL, NULL, NULL } diff --git a/src/types.c b/src/types.c index 1093a2b42..d21e0bf20 100644 --- a/src/types.c +++ b/src/types.c @@ -73,14 +73,14 @@ static size_t num_object_types = 0; /*-------------------------------------------------------------------------*/ static lpctype_t * -lpctype_new (void) +lpctype_new (void * p UNUSED MTRACE_DECL) /* Create a new lpctype_t instance. * .t_class and class dependant members are left uninitialized. */ { - lpctype_t *type = (lpctype_t*) xalloc(sizeof(lpctype_t)); + lpctype_t *type = (lpctype_t*) xalloc_pass(sizeof(lpctype_t)); type->ref = 1; type->t_static = false; type->array_of = NULL; @@ -116,7 +116,7 @@ lpctype_touch (lpctype_t *uniontype) /*-------------------------------------------------------------------------*/ lpctype_t * -get_struct_name_type (struct_name_t* name) +_get_struct_name_type (struct_name_t* name MTRACE_DECL) /* Create an lpctype_t for struct name . */ @@ -128,7 +128,7 @@ get_struct_name_type (struct_name_t* name) ref_lpctype(type); else { - name->lpctype = type = lpctype_new(); + name->lpctype = type = lpctype_new(NULL MTRACE_PASS); type->t_class = TCLASS_STRUCT; type->t_struct.name = ref_struct_name(name); type->t_struct.def_idx = USHRT_MAX; @@ -140,14 +140,14 @@ get_struct_name_type (struct_name_t* name) /*-------------------------------------------------------------------------*/ lpctype_t * -get_struct_type (struct_type_t* def) +_get_struct_type (struct_type_t* def MTRACE_DECL) /* Create an lpctype_t around , check for already * existing definitions. */ { - lpctype_t *type = get_struct_name_type(def->name); + lpctype_t *type = _get_struct_name_type(def->name MTRACE_PASS); type->t_struct.def = def; @@ -291,7 +291,7 @@ add_object_type (lpctype_t *type) /*-------------------------------------------------------------------------*/ static lpctype_t * -internal_get_object_type (string_t *prog, object_types_t otype) +internal_get_object_type (string_t *prog, object_types_t otype MTRACE_DECL) /* Create an lpctype_t for an (lw)object having in its program. * The name is normalized (removing a leading '/', check for double @@ -328,7 +328,7 @@ internal_get_object_type (string_t *prog, object_types_t otype) return ref_lpctype(result); } - result = lpctype_new(); + result = lpctype_new(NULL MTRACE_PASS); result->t_class = TCLASS_OBJECT; result->t_object.program_name = s; result->t_object.type = otype; @@ -348,7 +348,7 @@ internal_get_object_type (string_t *prog, object_types_t otype) /*-------------------------------------------------------------------------*/ lpctype_t * -get_object_type (string_t *prog) +_get_object_type (string_t *prog MTRACE_DECL) /* Create an lpctype_t for an object having in its program. * @@ -356,12 +356,12 @@ get_object_type (string_t *prog) */ { - return internal_get_object_type(prog, OBJECT_REGULAR); + return internal_get_object_type(prog, OBJECT_REGULAR MTRACE_PASS); } /* get_object_type() */ /*-------------------------------------------------------------------------*/ lpctype_t * -get_lwobject_type (string_t *prog) +_get_lwobject_type (string_t *prog MTRACE_DECL) /* Create an lpctype_t for an lwobject having in its program. * @@ -369,13 +369,13 @@ get_lwobject_type (string_t *prog) */ { - return internal_get_object_type(prog, OBJECT_LIGHTWEIGHT); + return internal_get_object_type(prog, OBJECT_LIGHTWEIGHT MTRACE_PASS); } /* get_lwobject_type() */ /*-------------------------------------------------------------------------*/ #ifdef USE_PYTHON lpctype_t * -get_python_type (int python_type_id) +_get_python_type (int python_type_id MTRACE_DECL) /* Create an lpctype_t for a Python type. * @@ -387,7 +387,7 @@ get_python_type (int python_type_id) if (type == NULL) { - type = lpctype_new(); + type = lpctype_new(NULL MTRACE_PASS); type->t_class = TCLASS_PYTHON; type->t_python.type_id = python_type_id; enter_python_type(python_type_id, type); @@ -426,7 +426,7 @@ remove_object_type (lpctype_t *type) /*-------------------------------------------------------------------------*/ lpctype_t * -get_array_type (lpctype_t *element) +_get_array_type (lpctype_t *element MTRACE_DECL) /* Create an array type with as the base type. */ @@ -441,7 +441,7 @@ get_array_type (lpctype_t *element) if (type != NULL) return ref_lpctype(type); - element->array_of = type = lpctype_new(); + element->array_of = type = lpctype_new(NULL MTRACE_PASS); type->t_class = TCLASS_ARRAY; type->t_array.element = ref_lpctype(element); if (element->t_class == TCLASS_ARRAY) @@ -460,7 +460,7 @@ get_array_type (lpctype_t *element) /*-------------------------------------------------------------------------*/ lpctype_t * -get_array_type_with_depth (lpctype_t *element, int depth) +_get_array_type_with_depth (lpctype_t *element, int depth MTRACE_DECL) /* Create an array whose depth is exactly . */ @@ -483,7 +483,7 @@ get_array_type_with_depth (lpctype_t *element, int depth) for (; depth > 0; depth--) { lpctype_t *old = type; - type = get_array_type(type); + type = _get_array_type(type MTRACE_PASS); free_lpctype(old); } return type; @@ -491,7 +491,7 @@ get_array_type_with_depth (lpctype_t *element, int depth) /*-------------------------------------------------------------------------*/ static lpctype_t * -make_union_type (lpctype_t *head, lpctype_t* member) +make_union_type (lpctype_t *head, lpctype_t* member MTRACE_DECL) /* Create a union type from and , this function * doesn't care about orderung. @@ -508,7 +508,7 @@ make_union_type (lpctype_t *head, lpctype_t* member) if (result) return ref_lpctype(result); - result = lpctype_new(); + result = lpctype_new(NULL MTRACE_PASS); result->t_class = TCLASS_UNION; result->t_union.head = ref_lpctype(head); result->t_union.member = ref_lpctype(member); @@ -520,7 +520,7 @@ make_union_type (lpctype_t *head, lpctype_t* member) /*-------------------------------------------------------------------------*/ lpctype_t * -get_union_type (lpctype_t *head, lpctype_t* member) +_get_union_type (lpctype_t *head, lpctype_t* member MTRACE_DECL) /* Create a union type from (maybe a union type) adding * (should not be a union type). is inserted at the correct @@ -551,7 +551,7 @@ get_union_type (lpctype_t *head, lpctype_t* member) do { insert = result; - result = get_union_type(result, next_member->t_union.member); + result = _get_union_type(result, next_member->t_union.member MTRACE_PASS); free_lpctype(insert); next_member = next_member->t_union.head; @@ -559,7 +559,7 @@ get_union_type (lpctype_t *head, lpctype_t* member) while (next_member->t_class == TCLASS_UNION); insert = result; - result = get_union_type(result, next_member); + result = _get_union_type(result, next_member MTRACE_PASS); free_lpctype(insert); return result; @@ -591,7 +591,7 @@ get_union_type (lpctype_t *head, lpctype_t* member) if (!lpctype_contains(insert_elem, member)) { lpctype_t *prev_result = result; - result = get_union_type(result, insert_elem); + result = _get_union_type(result, insert_elem MTRACE_PASS); free_lpctype(prev_result); } @@ -621,13 +621,13 @@ get_union_type (lpctype_t *head, lpctype_t* member) if (insert->t_class != TCLASS_UNION && insert > member) { - result = make_union_type(member, insert); + result = make_union_type(member, insert MTRACE_PASS); next_member = NULL; } else { next_member = insert->unions_of; /* make_union_type will change this. */ - result = make_union_type(insert, member); + result = make_union_type(insert, member MTRACE_PASS); } while (insert != head) @@ -639,7 +639,7 @@ get_union_type (lpctype_t *head, lpctype_t* member) } else insert = insert->unions_of; - result = make_union_type(result, insert->t_union.member); + result = make_union_type(result, insert->t_union.member MTRACE_PASS); free_lpctype(result->t_union.head); } @@ -648,7 +648,7 @@ get_union_type (lpctype_t *head, lpctype_t* member) /*-------------------------------------------------------------------------*/ static lpctype_t * -internal_get_common_type(lpctype_t *t1, lpctype_t* t2, bool find_one) +internal_get_common_type(lpctype_t *t1, lpctype_t* t2, bool find_one MTRACE_DECL) /* Determine the intersection of both types. * Returns NULL if there is no common type. @@ -744,8 +744,8 @@ internal_get_common_type(lpctype_t *t1, lpctype_t* t2, bool find_one) return NULL; else { - lpctype_t *common_element = get_common_type(t1->t_array.element, t2->t_array.element); - lpctype_t *result = get_array_type(common_element); + lpctype_t *common_element = _get_common_type(t1->t_array.element, t2->t_array.element MTRACE_PASS); + lpctype_t *result = _get_array_type(common_element MTRACE_PASS); free_lpctype(common_element); return result; } @@ -756,13 +756,13 @@ internal_get_common_type(lpctype_t *t1, lpctype_t* t2, bool find_one) while (true) { lpctype_t *base = t1->t_class == TCLASS_UNION ? t1->t_union.member : t1; - lpctype_t *common_base = get_common_type(t2, base); + lpctype_t *common_base = _get_common_type(t2, base MTRACE_PASS); lpctype_t *oldresult = result; if (find_one && common_base) return common_base; - result = get_union_type(result, common_base); + result = _get_union_type(result, common_base MTRACE_PASS); free_lpctype(common_base); free_lpctype(oldresult); @@ -789,14 +789,14 @@ has_common_type(lpctype_t *t1, lpctype_t* t2) */ { - lpctype_t *result = internal_get_common_type(t1, t2, true); + lpctype_t *result = internal_get_common_type(t1, t2, true MTRACE_ARG); free_lpctype(result); return (result != NULL); } /* has_common_type() */ /*-------------------------------------------------------------------------*/ lpctype_t * -get_common_type(lpctype_t *t1, lpctype_t* t2) +_get_common_type(lpctype_t *t1, lpctype_t* t2 MTRACE_DECL) /* Determine the intersection of both types. * Returns NULL if there is no common type. @@ -805,7 +805,7 @@ get_common_type(lpctype_t *t1, lpctype_t* t2) */ { - return internal_get_common_type(t1, t2, false); + return internal_get_common_type(t1, t2, false MTRACE_PASS); } /* get_common_type() */ /*-------------------------------------------------------------------------*/ diff --git a/src/types.h b/src/types.h index 1a372a41e..3de93d361 100644 --- a/src/types.h +++ b/src/types.h @@ -279,17 +279,29 @@ extern lpctype_t _lpctype_int, _lpctype_string, _lpctype_bytes, _lpctype_any_lwobject, _lpctype_void, _lpctype_unknown; -extern lpctype_t *get_struct_name_type(struct_name_t* name); -extern lpctype_t *get_struct_type(struct_type_t* def); -extern lpctype_t *get_object_type(string_t* prog); -extern lpctype_t *get_lwobject_type(string_t* prog); +#define get_struct_name_type(name) _get_struct_name_type(name MTRACE_ARG) +#define get_struct_type(def) _get_struct_type(def MTRACE_ARG) +#define get_object_type(prog) _get_object_type(prog MTRACE_ARG) +#define get_lwobject_type(prog) _get_lwobject_type(prog MTRACE_ARG) #ifdef USE_PYTHON -extern lpctype_t *get_python_type(int python_type_id); +#define get_python_type(python_type_id) _get_python_type(python_type_id MTRACE_ARG) #endif -extern lpctype_t *get_array_type(lpctype_t *element); -extern lpctype_t *get_array_type_with_depth(lpctype_t *element, int depth); -extern lpctype_t *get_union_type(lpctype_t *head, lpctype_t* member); -extern lpctype_t *get_common_type(lpctype_t *t1, lpctype_t* t2); +#define get_array_type(element) _get_array_type(element MTRACE_ARG) +#define get_array_type_with_depth(element,depth) _get_array_type_with_depth(element,depth MTRACE_ARG) +#define get_union_type(head,member) _get_union_type(head,member MTRACE_ARG) +#define get_common_type(t1,t2) _get_common_type(t1,t2 MTRACE_ARG) + +extern lpctype_t *_get_struct_name_type(struct_name_t* name MTRACE_DECL); +extern lpctype_t *_get_struct_type(struct_type_t* def MTRACE_DECL); +extern lpctype_t *_get_object_type(string_t* prog MTRACE_DECL); +extern lpctype_t *_get_lwobject_type(string_t* prog MTRACE_DECL); +#ifdef USE_PYTHON +extern lpctype_t *_get_python_type(int python_type_id MTRACE_DECL); +#endif +extern lpctype_t *_get_array_type(lpctype_t *element MTRACE_DECL); +extern lpctype_t *_get_array_type_with_depth(lpctype_t *element, int depth MTRACE_DECL); +extern lpctype_t *_get_union_type(lpctype_t *head, lpctype_t* member MTRACE_DECL); +extern lpctype_t *_get_common_type(lpctype_t *t1, lpctype_t* t2 MTRACE_DECL); extern bool has_common_type(lpctype_t *t1, lpctype_t* t2); extern void make_static_type(lpctype_t *src, lpctype_t *dest);