Files
mercury/runtime/mercury_wrapper.h
Zoltan Somogyi f6fafa150d Fix Mantis bug 314 for temp frames created by nondet procedures.
Also fix some bugs in related code, and improve the related debugging
infrastructure.

-------------------

runtime/mercury_stacks.[ch]:
   Fix bug 314 for temp frames created by nondet procedures. The fix will
   probably also work for *det* procedures that create temp frames on the
   nondet stack, but I can't think of a way to test that, because det
   procedures create such frames only in very specific circumstances,
   and I cannot think of a way to nest a recursive call inside those
   circumstances.

   The problem was that when we were creating new temp frames on
   the nondet stack, we did not check whether the current nondet stack segment
   had room for them. We now do.

   The stack trace tracing code needs to know the size of each nondet stack
   frame, since it uses the size to classify frames as temp or ordinary.
   The size is given by the difference in address between the address of the
   frame and the address of the previous frame. This difference would yield
   an incorrect size and hence an incorrect frame classification if a temp
   frame were allowed to have a frame on a different segment as its
   immediate predecessor.

   We prevent this by putting an ordinary (i.e. non-temp) frame at the bottom
   of every new nondet stack segment as a sentinel. We hand-build this frame,
   since it is not an "ordinary" ordinary frame. It is not created by a call,
   so it has no meaningful success continuation, and since it does not make
   any calls, no other frame's success continuation can point to it either.

   If backtracking reaches this sentinel frame, we use this fact to free
   all the segments beyond the one the sentinel frame is in, but keep the
   frame the sentinel frame is in, since we are likely to need it again.

   Document the reason why MR_incr_sp_leaf() does not have to check
   whether a new stack segment is needed. (See the fix to llds_out_instr.m
   below.)

runtime/mercury_stack_trace.[ch]:
   When traversing the nondet stack, treat the sentinel frame specially.
   We have to, since it is an ordinary frame (i.e. it is not a temp frame),
   but it is not an "ordinary" ordinary frame: it does not make calls,
   and hence calls cannot return to it, and it does not return to any
   other frame either. It therefore does not have the layout structures
   (label and proc) that the nondet stack traversal expects to find.

   Fix an old bug: the nondet stack traversal used a simple directional
   pointer comparison to check whether it has reached the bottom of the nondet
   stack. This is NOT guaranteed to work in the presence of stack segments:
   depending on exactly what addresses new stack segments get, a stack frame
   can have an address BELOW the address of the initial stack frame
   even if it is logically ABOVE that stack frame.

   Another old bug was that a difference between two pointers, which could
   be 64 bit, was stored in an int, which could be 32 bit.

   The nondet stack traversal code used a similar directional comparison
   to implement optionally stopping at an arbitrary point on the nondet stack.
   Fixing this facility (the limit_addr parameter of MR_dump_nondet_stack)
   while preserving reasonable efficiency would not be trivial, but it would
   also be pointless, since the facility is not actually used. This diff
   deletes the parameter instead.

   Move some loop invariant code out of its loop.

trace/mercury_trace_cmd_developer.c:
trace/mercury_trace_external.c:
   Don't pass the now-deleted parameter to mercury_stack_trace.c.

runtime/mercury_wrapper.c:
   Record the zone of the initial nondet stack frame, since the fix
   of mercury_stack_trace.c needs that info, and it is much more efficient
   to set it up just once.

tests/hard_coded/bug314.{m,exp}:
   The regression test for this bug.

tests/hard_coded/Mercury.options:
   Compile the new test case with the options it needs.

tests/hard_coded/Mmakefile:
   Enable the new test case.

-------------------

runtime/mercury_wrapper.c:
   The compiler knows the number of words in a stack frame it is creating,
   not necessarily the number of bytes (though it could put bounds on that
   from the number of tag bits). Since this size must sync with the runtime,
   change the runtime's variable holding this size to also be in words.

   Note that similar changes would also be beneficial for other sizes.

compiler/llds_out_instr.m:
   Conform to the change in mercury_wrapper.c, fixing an old bug
   (mercury_wrapper.c reserved 128 BYTES for leaf procedures, but
   llds_out_instr.m was using that space for procedures whose frames
   were up to 128 WORDS in size.)

compiler/mercury_memory.c:
   Conform to the change in mercury_wrapper.c.

-------------------

runtime/mercury_memory_zones.h:
   Instead of starting to use EVERY zone at a different offset, do this
   only for the INITIAL zones in each memory area, since only on these
   is it useful. When the program first starts up, it WILL be using
   the initial parts of the det stack, nondet stack and heap, so it is
   useful to make sure that these do not collide in the cache. However,
   when we allocate e.g. the second zone in e.g. the nondet stack, we are
   no more likely to be beating on the initial part of any segment
   of the det stack than on any other part of such segments.

   If a new debug macro, MR_DEBUG_STACK_SEGMENTS_SET_SIZE is set (to an int),
   use only that many words in each segment. This allows the segment switchover
   code to be exercised and debugged with smaller test cases.

runtime/mercury_conf_param.h:
   Document the MR_DEBUG_STACK_SEGMENTS_SET_SIZE macro.

   Convert this file to four-space indentation with tabs expanded.

-------------------

runtime/mercury_overflow.h:
   Make abort messages from overflows and underflows more useful by including
   more information.

runtime/mercury_overflow.c:
   Add a new function to help with the better abort messages.
   Since this file did not exist before, create it.

runtime/Mmakefile:
   Add the new source file to the list of source files.

-------------------

runtime/mercury_debug.[ch]:
   Fix problems with the formatting of the debugging output from existing
   functions.

   Add new functions for dumping info about memory zones.

   Factor out some common code.

   Convert the header file to four-space indentation.

-------------------

runtime/mercury_grade.c:
   Generate an error if stack segments are specified together with stack
   extension

-------------------

trace/.gitignore:
util/.gitignore:
tests/debugger/.gitignore:
   List some more files.

-------------------

runtime/mercury_context.c:
runtime/mercury_engine.[ch]:
runtime/mercury_misc.h:
compiler/notes/failure.html:
   Fix white space.
2014-04-18 02:02:35 +10:00

367 lines
13 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1994-2011 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** mercury_wrapper.h - defines the interface to mercury_wrapper.c.
** See mercury_wrapper.c for documentation.
*/
#ifndef MERCURY_WRAPPER_H
#define MERCURY_WRAPPER_H
#include "mercury_regs.h" /* needs to come first */
#include <stddef.h> /* for `size_t' */
#include "mercury_std.h" /* for `MR_bool' */
#include "mercury_stack_layout.h" /* for `MR_LabelLayout' etc */
#include "mercury_trace_base.h" /* for `MR_trace_port' */
#include "mercury_stacks.h" /* for `MR_{Cut,Generator}StackFrame' */
#include "mercury_type_info.h" /* for `MR_TypeCtorInfo' */
#include "mercury_library_types.h" /* for `MercuryFilePtr' */
#include "mercury_complexity.h" /* for `MR_ComplexityProc' */
#include <stdio.h> /* for `FILE' */
/*
** mercury_runtime_init() does some stuff to initialize the garbage collector
** and the Mercury engine's data areas, and then calls io__init_state/2
** in the Mercury library to initialize the io__state.
*/
extern void mercury_runtime_init(int argc, char **argv);
/*
** mercury_runtime_main() basically just calls main/2,
** with a bit of debugging scaffolding around it.
*/
extern void mercury_runtime_main(void);
/*
** mercury_runtime_terminate() does any necessary cleanup,
** and then returns mercury_exit_status.
*/
extern int mercury_runtime_terminate(void);
/*
** MR_init_conservative_GC() initializes the conservative collector.
** The conservative collector can be either the Boehm et al collector,
** or the MPS (Memory Pool System) kit collector. This function is normally
** called from mercury_runtime_init().
*/
#ifdef MR_CONSERVATIVE_GC
extern void MR_init_conservative_GC(void);
#endif
/*
** The following global variables are set by mercury_init() on startup.
** The entry points are set based on the options to mkinit.c.
** The address_of_foo pointers are set to the address of
** the corresponding foo.
*/
#ifdef MR_HIGHLEVEL_CODE
extern void MR_CALL (*MR_program_entry_point)(void);
/* normally main_2_p_0 */
#else
extern MR_Code *MR_program_entry_point;
/* normally mercury__main_2_0; */
#endif
#ifdef MR_HIGHLEVEL_CODE
extern void MR_dummy_main(void);
#endif
/****************************************************************************/
/*
** The values of the variables in this section of mercury_wrapper.h
** are defined by the program's _init.c file, which is generated by mkinit.
*/
/*
** MR_runtime_flags holds program specific options, treated the same
** as MERCURY_OPTIONS, that are burned into the program by mkinit.
*/
extern const char *MR_runtime_flags;
extern void (*MR_library_initializer)(void);
extern void (*MR_library_finalizer)(void);
extern void (*MR_io_stderr_stream)(MercuryFilePtr *);
extern void (*MR_io_stdout_stream)(MercuryFilePtr *);
extern void (*MR_io_stdin_stream)(MercuryFilePtr *);
extern void (*MR_io_print_to_cur_stream)(MR_Word, MR_Word);
extern void (*MR_io_print_to_stream)(MR_Word, MercuryFilePtr, MR_Word);
extern void (*MR_address_of_mercury_init_io)(void);
extern void (*MR_address_of_init_modules)(void);
extern void (*MR_address_of_init_modules_type_tables)(void);
extern void (*MR_address_of_init_modules_debugger)(void);
#ifdef MR_RECORD_TERM_SIZES
extern void (*MR_address_of_init_modules_complexity)(void);
#endif
#ifdef MR_DEEP_PROFILING
extern void (*MR_address_of_write_out_proc_statics)(FILE *deep_fp,
FILE *procrep_fp);
#endif
#ifdef MR_THREADSCOPE
extern void (*MR_address_of_init_modules_threadscope_string_table)
(void);
#endif
extern void (*MR_address_of_init_modules_required)(void);
extern void (*MR_address_of_final_modules_required)(void);
extern MR_TypeCtorInfo MR_type_ctor_info_for_univ;
extern MR_TypeCtorInfo MR_type_info_for_type_info;
extern MR_TypeCtorInfo MR_type_info_for_pseudo_type_info;
extern MR_TypeInfo MR_type_info_for_list_of_univ;
extern MR_TypeInfo MR_type_info_for_list_of_int;
extern MR_TypeInfo MR_type_info_for_list_of_char;
extern MR_TypeInfo MR_type_info_for_list_of_string;
extern MR_TypeInfo MR_type_info_for_list_of_type_info;
extern MR_TypeInfo MR_type_info_for_list_of_pseudo_type_info;
#ifdef MR_CONSERVATIVE_GC
extern void (*MR_address_of_init_gc)(void);
#endif
/*
** MR_trace_getline(const char *, FILE *, FILE *) and
** MR_trace_get_command(const char *, FILE *, FILE *) are defined in
** trace/mercury_trace_internal.c but are called in browser/util.m.
** As we cannot do direct calls from browser/ to trace/, we do indirect
** calls via the following pointers.
*/
extern char * (*MR_address_of_trace_getline)(const char *,
FILE *, FILE *);
extern char * (*MR_address_of_trace_get_command)(const char *,
FILE *, FILE *);
/*
** MR_trace_browse_all_on_level() is defined in trace/mercury_trace_vars.c
** but may be called from runtime/mercury_stack_trace.c. As we can not do
** direct calls from runtime/ to trace/, we do an indirect call via the
** function pointer MR_address_of_trace_browse_all_on_level.
*/
extern const char *(*MR_address_of_trace_browse_all_on_level)(FILE *,
const MR_LabelLayout *, MR_Word *, MR_Word *,
int, MR_bool);
/*
** MR_trace_init_external() and MR_trace_final_external() are defined
** in trace/mercury_trace_external.c but are called in
** runtime/mercury_trace_base.c. As we can not do direct calls from
** runtime/ to trace/, we do an indirect call via a function
** pointer MR_address_of_trace_init_external.
*/
extern void (*MR_address_of_trace_init_external)(void);
extern void (*MR_address_of_trace_final_external)(void);
/*
** MR_exec_trace_func_ptr is set to either MR_trace_real
** (trace/mercury_trace.c), or MR_trace_fake (runtime/mercury_trace_base.c),
** depending on whether execution tracing was enabled when creating the _init.c
** file.
*/
extern MR_Code *(*MR_exec_trace_func_ptr)(const MR_LabelLayout *);
/*
** If the init file was built with tracing enabled, then
** MR_address_of_trace_interrupt_handler points to
** MR_trace_interrupt_handler, otherwise it is NULL.
*/
extern void (*MR_address_of_trace_interrupt_handler)(void);
/*
** If the init file was built with tracing enabled, then
** MR_register_module_layout points to MR_register_module_layout_real,
** otherwise it is NULL.
*/
extern void (*MR_register_module_layout)(const MR_ModuleLayout *);
/****************************************************************************/
extern void MR_do_init_modules(void);
extern void MR_do_init_modules_type_tables(void);
extern void MR_do_init_modules_debugger(void);
#ifdef MR_RECORD_TERM_SIZES
extern void MR_do_init_modules_complexity(void);
/*
** MR_complexity_preds_size gives the number of elements in the
** MR_complexity_preds array.
*/
extern MR_ComplexityProc *MR_complexity_procs;
extern int MR_num_complexity_procs;
#endif
extern const char *MR_progname;
extern int mercury_argc;
extern char **mercury_argv;
extern int mercury_exit_status;
/* sizes of the data areas, *including* the red zone size */
extern size_t MR_heap_size;
extern size_t MR_detstack_size;
extern size_t MR_nondetstack_size;
extern size_t MR_small_detstack_size;
extern size_t MR_small_nondetstack_size;
extern size_t MR_solutions_heap_size;
extern size_t MR_trail_size;
extern size_t MR_global_heap_size;
extern size_t MR_debug_heap_size;
extern size_t MR_genstack_size;
extern size_t MR_cutstack_size;
extern size_t MR_pnegstack_size;
extern size_t MR_gen_detstack_size;
extern size_t MR_gen_nondetstack_size;
/* sizes of the red zones */
extern size_t MR_heap_zone_size;
extern size_t MR_detstack_zone_size;
extern size_t MR_nondetstack_zone_size;
extern size_t MR_solutions_heap_zone_size;
extern size_t MR_trail_zone_size;
extern size_t MR_global_heap_zone_size;
extern size_t MR_debug_heap_zone_size;
extern size_t MR_genstack_zone_size;
extern size_t MR_cutstack_zone_size;
extern size_t MR_pnegstack_zone_size;
extern size_t MR_gen_detstack_zone_size;
extern size_t MR_gen_nondetstack_zone_size;
/* heap margin for MLDS->C accurate GC (documented in mercury_wrapper.c) */
extern size_t MR_heap_margin_size;
/* heap expansion factor for accurate GC (see mercury_accurate_gc.c) */
extern double MR_heap_expansion_factor;
/* margin for the stack segment test (documented in mercury_wrapper.c) */
extern size_t MR_stack_margin_size_words;
/* number of outstanding contexts we can create per thread (soft limit) */
extern MR_Unsigned MR_contexts_per_thread;
/*
** The number of outstanding contexts we can create
** (MR_contexts_per_thread * MR_num_threads).
*/
extern MR_Unsigned MR_max_outstanding_contexts;
/*
** The number of contexts to create per loop controlled loop.
*/
extern MR_Unsigned MR_num_contexts_per_loop_control;
extern MR_Unsigned MR_num_threads;
#if defined(MR_THREAD_SAFE) && defined(MR_LL_PARALLEL_CONJ)
/*
** This is used to set MR_granularity_wsdeque_length based on the value of
** MR_num_threads. A value of 2 says, allow twice as many threads in a
** context's wsdeque than mercury engines before granularity control has an
** effect.
*/
extern MR_Unsigned MR_granularity_wsdeque_length_factor;
/*
** The length of a context's wsdeque before granularity control has an effect.
*/
extern MR_Unsigned MR_granularity_wsdeque_length;
#endif
/* file names for the mdb debugging streams */
extern const char *MR_mdb_in_filename;
extern const char *MR_mdb_out_filename;
extern const char *MR_mdb_err_filename;
/* should mdb be started in a window */
extern MR_bool MR_mdb_in_window;
/* should the declarative debugger print progress messages */
extern MR_bool MR_mdb_decl_print_progress;
/* should mdb be silent for benchmarking purposes */
extern MR_bool MR_mdb_benchmark_silent;
/* use readline() in the debugger even if the input stream is not a tty */
extern MR_bool MR_force_readline;
/* size of the primary cache */
extern size_t MR_pcache_size;
/* low level debugging */
extern MR_bool MR_check_space;
extern MR_Word *MR_watch_addr;
extern MR_CallSiteDynamic *MR_watch_csd_addr;
extern MR_bool MR_watch_csd_started;
extern const char *MR_watch_csd_start_name;
extern unsigned long MR_lld_cur_call;
extern MR_bool MR_lld_print_enabled;
extern MR_bool MR_lld_print_name_enabled;
extern MR_bool MR_lld_print_csd_enabled;
extern MR_bool MR_lld_print_region_enabled;
extern MR_bool MR_lld_print_always_enabled;
extern const char *MR_lld_start_name;
extern unsigned MR_lld_start_block;
extern unsigned long MR_lld_start_until;
extern unsigned long MR_lld_csd_until;
extern unsigned long MR_lld_print_min;
extern unsigned long MR_lld_print_max;
extern char *MR_lld_print_more_min_max;
/* timing */
extern int MR_user_time_at_start;
extern int MR_user_time_at_last_stat;
extern int MR_real_time_at_start;
extern int MR_real_time_at_last_stat;
/* time profiling */
enum MR_TimeProfileMethod {
MR_profile_real_time, /* i.e. ITIMER_REAL */
MR_profile_user_time, /* i.e. ITIMER_VIRTUAL */
MR_profile_user_plus_system_time /* i.e. ITIMER_PROF */
};
extern enum MR_TimeProfileMethod MR_time_profile_method;
extern MR_bool MR_profiling;
extern MR_bool MR_print_deep_profiling_statistics;
#ifdef MR_TYPE_CTOR_STATS
typedef struct MR_TypeStat_Struct MR_TypeStat;
extern MR_TypeStat MR_type_stat_mer_unify;
extern MR_TypeStat MR_type_stat_c_unify;
extern MR_TypeStat MR_type_stat_mer_compare;
extern MR_TypeStat MR_type_stat_c_compare;
extern void MR_register_type_ctor_stat(MR_TypeStat *type_stat,
MR_TypeCtorInfo type_ctor_info);
#endif
/* This is used by compiler/mlds_to_gcc.m. */
extern const char *MR_make_argv(const char *, char **, char ***, int *);
extern void MR_setup_call_intervals(char **more_str_ptr,
unsigned long *min_ptr, unsigned long *max_ptr);
#endif /* not MERCURY_WRAPPER_H */