/* ** vim: ts=4 sw=4 expandtab */ /* ** Copyright (C) 1994-2007, 2009-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_engine.h - definitions for the Mercury runtime engine. ** ** For documentation, see also the comments in mercury_engine.c. */ #ifndef MERCURY_ENGINE_H #define MERCURY_ENGINE_H /* ** Include mercury_regs.h first so that we don't have any function prototypes ** before the global register declarations. */ #include "mercury_regs.h" /* for MR_NUM_REAL_REGS */ #include #include "mercury_std.h" /* for `MR_bool' */ #include "mercury_types.h" /* for `MR_Code *' */ #include "mercury_float.h" /* for `MR_Float' */ #include "mercury_goto.h" /* for `MR_define_entry()' */ #include "mercury_thread.h" /* for pthread types */ #include "mercury_context.h" /* for MR_Context, MR_IF_USE_TRAIL */ #include "mercury_conf.h" /* for MR_CONSERVATIVE_GC */ /*---------------------------------------------------------------------------*/ /* ** Global flags that control the behaviour of the Mercury engine(s) */ extern MR_bool MR_debugflag[]; /* ** These #defines, except MR_MAXFLAG, should not be used anywhere ** except in the immediately following block of #defines, and in the ** array that maps these names to their slots in the source file. */ #define MR_PROGFLAG 0 #define MR_GOTOFLAG 1 #define MR_CALLFLAG 2 #define MR_HEAPFLAG 3 #define MR_DETSTACKFLAG 4 #define MR_NONDETSTACKFLAG 5 #define MR_FINALFLAG 6 #define MR_MEMFLAG 7 #define MR_SREGFLAG 8 #define MR_TRACEFLAG 9 #define MR_TABLEFLAG 10 #define MR_TABLEHASHFLAG 11 #define MR_TABLESTACKFLAG 12 #define MR_UNBUFFLAG 13 #define MR_AGC_FLAG 14 #define MR_ORDINARY_REG_FLAG 15 #define MR_ANY_REG_FLAG 16 #define MR_PRINT_LOCN_FLAG 17 #define MR_LLD_DEBUG_ENABLED_FLAG 18 #define MR_NOT_NEAREST_FLAG 19 #define MR_DEBUG_SLOTS_FLAG 20 #define MR_DEEP_PROF_DEBUG_FILE_FLAG 21 #define MR_STACK_EXTEND_FLAG 22 #define MR_DETAILFLAG 23 #define MR_MAXFLAG 24 /* MR_DETAILFLAG should be the last real flag */ /* ** The macros control different kinds of low level debugging messages. ** Usually, their values are all false. ** ** MR_progdebug controls whether we want to get several mostly explicitly ** programmed diagnostics. ** ** MR_sregdebug controls whether we want to print the values of the special ** registers (e.g. those that point to the stack) at some diagnostic points. ** ** MR_ordregdebug controls whether we want to print the values of the ordinary ** registers (e.g. r1, r2 etc) at some diagnostic points. ** ** MR_anyregdebug controls whether we want to print the values of the any ** registers, either special or ordinary, at some diagnostic points. ** ** MR_gotodebug controls whether we should generate diagnostics at gotos. ** ** MR_calldebug controls whether we should generate diagnostics when control ** crosses procedure boundaries, i.e. calls, exits, redos and fails. ** ** MR_detstackdebug and MR_nondetstackdebug control whether we should generate ** diagnostics when incrementing and decrementing the pointers to the ** respective stacks. ** ** MR_heapdebug controls whether we should generate diagnostics when we ** allocate memory on the heap. ** ** MR_tabledebug controls whether we should generate diagnostics for tabling ** operations. MR_tablestackdebug control whether these should include the ** contents of stack segments manipulated by minimal model tabling. ** MR_hashdebug controls whether these should include details of hash table ** accesses. ** ** MR_agcdebug controls whether we should generate diagnostics for accurate ** gc operations. ** ** MR_detaildebug controls whether we want more or less detail in some ** diagnostics. ** ** MR_unbufdebug controls whether the runtime will make stdout and stderr ** unbuffered. ** ** MR_memdebug controls whether we want to get diagnostics on the setup of ** memory zones. ** ** MR_finaldebug controls whether we want to get diagnostics showing how ** execution reaches the end of the program. ** ** MR_printlocndebug controls whether we want to get diagnostics showing how ** the runtime system looks up locations recorded in RTTI data structures. ** ** MR_lld_debug_enabled turns on the generation of diagnostic output even when ** they would otherwise be disabled. ** ** MR_not_nearest_flag, if set, tells minimal model tabling to save stack ** segments only to the nearest generator, not to the nearest common ancestor ** of the consumer being suspended and its generator. ** ** MR_debug_slots_flag controls whether dumps of nondet stack frames will ** print the values of the fixed stack slots used by the debugger, in the ** stack frames of procedures compiled with debugging. ** ** MR_deep_prof_debug_file_flag, if set, causes the runtime, whenever it is ** generating a Deep.data file, to also generate a human-readable Deep.debug ** file. ** ** MR_stack_extend_debug controls whether the runtime prints diagnostics ** whenever it extends a stack. */ #define MR_progdebug MR_debugflag[MR_PROGFLAG] #define MR_gotodebug MR_debugflag[MR_GOTOFLAG] #define MR_calldebug MR_debugflag[MR_CALLFLAG] #define MR_heapdebug MR_debugflag[MR_HEAPFLAG] #define MR_detstackdebug MR_debugflag[MR_DETSTACKFLAG] #define MR_nondetstackdebug MR_debugflag[MR_NONDETSTACKFLAG] #define MR_finaldebug MR_debugflag[MR_FINALFLAG] #define MR_memdebug MR_debugflag[MR_MEMFLAG] #define MR_sregdebug MR_debugflag[MR_SREGFLAG] #define MR_tracedebug MR_debugflag[MR_TRACEFLAG] #define MR_tabledebug MR_debugflag[MR_TABLEFLAG] #define MR_hashdebug MR_debugflag[MR_TABLEHASHFLAG] #define MR_tablestackdebug MR_debugflag[MR_TABLESTACKFLAG] #define MR_unbufdebug MR_debugflag[MR_UNBUFFLAG] #define MR_agc_debug MR_debugflag[MR_AGC_FLAG] #define MR_ordregdebug MR_debugflag[MR_ORDINARY_REG_FLAG] #define MR_anyregdebug MR_debugflag[MR_ANY_REG_FLAG] #define MR_printlocndebug MR_debugflag[MR_PRINT_LOCN_FLAG] #define MR_lld_debug_enabled MR_debugflag[MR_LLD_DEBUG_ENABLED_FLAG] #define MR_not_nearest_flag MR_debugflag[MR_NOT_NEAREST_FLAG] #define MR_debug_slots_flag MR_debugflag[MR_DEBUG_SLOTS_FLAG] #define MR_deep_prof_debug_file_flag MR_debugflag[\ MR_DEEP_PROF_DEBUG_FILE_FLAG] #define MR_stack_extend_debug MR_debugflag[MR_STACK_EXTEND_FLAG] #define MR_detaildebug MR_debugflag[MR_DETAILFLAG] typedef struct { const char *MR_debug_flag_name; int MR_debug_flag_index; } MR_Debug_Flag_Info; extern MR_Debug_Flag_Info MR_debug_flag_info[MR_MAXFLAG]; /* ** MR_setjmp and MR_longjmp are wrappers around setjmp and longjmp to ensure ** that ** call C -> setjmp -> call Mercury -> call C -> longjmp ** works correctly. This is used by the exception handling code for ** the ODBC interface, and probably shouldn't be used for anything else. */ typedef struct { jmp_buf *mercury_env; /* used to save MR_ENGINE(MR_eng_jmp_buf) */ jmp_buf env; /* used by calls to setjmp and longjmp */ MR_Word *saved_succip; MR_Word *saved_sp; MR_Word *saved_curfr; MR_Word *saved_maxfr; MR_IF_USE_TRAIL(MR_TrailEntry *saved_trail_ptr;) MR_IF_USE_TRAIL(MR_Unsigned saved_ticket_counter;) MR_IF_USE_TRAIL(MR_Unsigned saved_ticket_high_water;) #if MR_NUM_REAL_REGS > 0 MR_Word regs[MR_NUM_REAL_REGS]; #endif /* MR_NUM_REAL_REGS > 0 */ } MR_jmp_buf; /*---------------------------------------------------------------------------*/ /* ** Replacements for setjmp() and longjmp() that work ** across calls to Mercury code. */ /* ** MR_setjmp(MR_jmp_buf *env, longjmp_label) ** ** Save MR_ENGINE(MR_eng_jmp_buf), save the Mercury state, call setjmp(env), ** then fall through. ** ** When setjmp returns via a call to longjmp, control will pass to ** longjmp_label. ** ** Notes: ** - The Mercury registers must be valid before the call to MR_setjmp. ** - The general-purpose registers MR_r1, MR_r2... are not restored ** and must be saved by the caller. ** - In grades without conservative garbage collection, the caller must save ** and restore hp, sol_hp, heap_zone and solutions_heap_zone. */ #define MR_setjmp(setjmp_env, longjmp_label) \ do { \ (setjmp_env)->mercury_env = MR_ENGINE(MR_eng_jmp_buf); \ MR_save_regs_to_mem((setjmp_env)->regs); \ (setjmp_env)->saved_succip = MR_succip; \ (setjmp_env)->saved_sp = MR_sp; \ (setjmp_env)->saved_curfr = MR_curfr; \ (setjmp_env)->saved_maxfr = MR_maxfr; \ MR_IF_USE_TRAIL((setjmp_env)->saved_trail_ptr = MR_trail_ptr); \ MR_IF_USE_TRAIL((setjmp_env)->saved_ticket_counter = \ MR_ticket_counter); \ MR_IF_USE_TRAIL((setjmp_env)->saved_ticket_high_water = \ MR_ticket_high_water); \ if (setjmp((setjmp_env)->env)) { \ MR_ENGINE(MR_eng_jmp_buf) = (setjmp_env)->mercury_env; \ MR_restore_regs_from_mem((setjmp_env)->regs); \ MR_succip_word = (MR_Word) (setjmp_env)->saved_succip; \ MR_sp_word = (MR_Word) (setjmp_env)->saved_sp; \ MR_curfr_word = (MR_Word) (setjmp_env)->saved_curfr; \ MR_maxfr_word = (MR_Word) (setjmp_env)->saved_maxfr; \ MR_IF_USE_TRAIL(MR_trail_ptr = (setjmp_env)->saved_trail_ptr); \ MR_IF_USE_TRAIL(MR_ticket_counter = \ (setjmp_env)->saved_ticket_counter); \ MR_IF_USE_TRAIL(MR_ticket_high_water = \ (setjmp_env)->saved_ticket_high_water); \ goto longjmp_label; \ } \ } while (0) /* ** MR_longjmp(MR_jmp_buf *env) ** ** Call longjmp(), MR_setjmp() will handle the rest. */ #define MR_longjmp(setjmp_env) longjmp((setjmp_env)->env, 1) /*---------------------------------------------------------------------------*/ /* ** The Mercury engine structure. Normally there is one of these for each ** Posix thread. It contains the following fields. ** ** fake_reg The fake reg vector for this engine. ** ** hp The heap pointer for this engine. ** ** sol_hp The solutions heap pointer for this engine. ** ** global_hp The global heap pointer for this engine. ** ** MR_eng_parent_sp ** The stack pointer of the parent contexts' stack frame from ** which this execution was forked. This is used to implement ** parallel conjunctions and enable a parallel conjunct to read ** it's input from it's parent, and to write back it's output. ** ** this_context Points to the "backing store" for the context currently ** executing on this engine. ** ** context Stores all the context information for the context currently ** executing in this engine. ** ** Conceptually, we could access all information relating to the ** current context via the MR_eng_this_context field. However, ** that would require an extra indirection on most accesses, ** including all accesses to the stack, abstract machine registers ** etc. That would be too high a cost. We therefore bodily include ** a context into the engine (in the MR_eng_context) field, and ** load most of the things pointed to by the MR_eng_this_context ** field into MR_eng_context. "Most", not "all", because some ** fields are so rarely accessed that we don't expect the extra ** cost of context switching to be compensated for by reduced ** access costs between context switches. These fields are ** therefore accessed directly via MR_eng_this_context. The big ** comment in mercury_context.h documents, for each field of the ** context structure, whether it is accessed by MR_eng_context or ** via MR_eng_this_context. ** ** MR_init_thread, invoked by mercury_runtime_init in ** mercury_wrapper.c, creates the initial MR_eng_this_context ** for the engine, and then invokes MR_load_context to copy the ** info from there into the MR_eng_context field. ** ** float_reg ** The float reg vector for this engine. This exists only if ** MR_BOXED_FLOAT is defined, i.e. when sizeof(MR_Float) > ** sizeof(MR_Word). ** ** trail_ptr ** ticket_counter ** ticket_high_water ** These fields correspond to the similarly named global ** variables declared in mercury_trail.h. They represent ** the state of the trail for the context that this engine ** is executing. These fields only exist in parallel trailing ** grades; in other trailing grades we use the aforementioned ** globals to store the trail state. ** ** main_context The context of the main computation. The owner_generator field ** of this context must be NULL. ** ** gen_contexts The contexts of the active generators in this engine. ** The owner_generator fields of these contexts will point ** to their generators. ** ** free_contexts ** Contexts that used to belong to active generators, but which ** are no longer needed. They are cached here to allow new ** generators to be created without redoing the work required ** to allocate a new context. ** ** owner_thread ** c_depth ** These fields are used to ensure that when a thread ** executing C code calls the Mercury engine associated with that ** thread, the Mercury code will finish in the same engine and ** return appropriately. Each time C calls Mercury in a thread, ** the c_depth is incremented, and the owner_thread and c_depth ** values of the current engine are pushed onto the "saved_owners" ** stack of the current context. When a context is about to return ** from Mercury code back into C code, we pop the top entry off the ** context's saved_owners stack and check that the context is ** running on the right engine. If not, we reschedule the context ** such that it can only be picked up by the correct engine when ** that engine is available. When the call into the Mercury code ** finishes, c_depth is decremented. ** ** cpu_clock_ticks_offset ** The offset to be added to the CPU's TSC to give a time relative ** to the start of the program. ** ** ts_buffer ** The buffer object used by threadscope for this engine. ** ** id The ID of this engine which is used by threadscope. ** ** next_spark_id ** In threadscope grades sparks are given IDs to help us track ** them. This and MR_eng_id is used to allocate unique IDs. ** ** spark_deque The sparks generated by contexts executing on this engine. ** ** victim_counter ** The engine id of this engines' next victim for work stealing. ** ** jmp_buf The jump buffer used by library/exception.m to return to the ** runtime system on otherwise unhandled exceptions. ** ** exception This field is used by library/exception.m to return the ** identity of the exception that terminates the execution of an ** engine to the runtime. ** ** heap_zone The heap zone for this engine. ** ** solutions_heap_zone ** The solutions heap zone for this engine. We store terms on this ** heap temporarily while looking for more solutions in an ** all-solutions predicate. ** ** global_heap_zone ** The global heap zone for this engine. We store terms on this ** heap when we want to make them survive resets of hp by ** backtracking, e.g. for global data structures in the debugger. ** ** heap_zone2 The other heap zone in our two-space collector. ** ** debug_heap_zone ** A zone used for debugging the accurate gc. Probably not ** terribly functional. */ typedef struct MR_mercury_engine_struct { MR_Word MR_eng_fake_reg[MR_MAX_FAKE_REG]; #ifndef MR_CONSERVATIVE_GC MR_Word *MR_eng_hp; MR_Word *MR_eng_sol_hp; MR_Word *MR_eng_global_hp; #endif #ifdef MR_LL_PARALLEL_CONJ MR_Word *MR_eng_parent_sp; #endif MR_Context *MR_eng_this_context; MR_Context MR_eng_context; #ifdef MR_BOXED_FLOAT MR_Float MR_eng_float_reg[MR_MAX_VIRTUAL_F_REG]; #endif #if defined(MR_THREAD_SAFE) && defined(MR_USE_TRAIL) MR_TrailEntry *MR_eng_trail_ptr; MR_Unsigned MR_eng_ticket_counter; MR_Unsigned MR_eng_ticket_high_water; #endif #ifdef MR_USE_MINIMAL_MODEL_OWN_STACKS MR_Context *MR_eng_main_context; MR_Dlist *MR_eng_gen_contexts; /* elements are MR_Context */ MR_Dlist *MR_eng_free_contexts; /* elements are MR_Context */ #endif #ifdef MR_THREAD_SAFE MR_EngineId MR_eng_id; MercuryThread MR_eng_owner_thread; MR_Unsigned MR_eng_c_depth; #ifdef MR_THREADSCOPE /* ** For each profiling event add this offset to the time so that events on ** different engines that occur at the same time have the same time in ** clock ticks. */ MR_int_least64_t MR_eng_cpu_clock_ticks_offset; struct MR_threadscope_event_buffer *MR_eng_ts_buffer; MR_uint_least32_t MR_eng_next_spark_id; #endif #ifdef MR_LL_PARALLEL_CONJ MR_SparkDeque MR_eng_spark_deque; MR_EngineId MR_eng_victim_counter; #endif #endif jmp_buf *MR_eng_jmp_buf; MR_Word *MR_eng_exception; #ifndef MR_CONSERVATIVE_GC MR_MemoryZone *MR_eng_heap_zone; #ifdef MR_MIGHT_RECLAIM_HP_ON_FAILURE MR_MemoryZone *MR_eng_solutions_heap_zone; MR_MemoryZone *MR_eng_global_heap_zone; #endif #endif #ifdef MR_NATIVE_GC MR_MemoryZone *MR_eng_heap_zone2; #ifdef MR_DEBUG_AGC_PRINT_VARS MR_MemoryZone *MR_eng_debug_heap_zone; #endif #endif } MercuryEngine; /* ** MR_engine_base refers to the engine in which execution is taking place. ** In the non-thread-safe situation, it is just a global variable. ** In the thread-safe situation, MR_engine_base is either a global ** register (if one is available), a thread-local variable (if compiler ** support is available), or a macro that accesses thread-local storage. ** We provide two macros, MR_ENGINE(x) and MR_CONTEXT(x), ** that can be used in all three kinds of situations to refer to fields ** of the engine structure, and to fields of the engine's current context. */ #ifdef MR_THREAD_SAFE #ifdef MR_THREAD_LOCAL_STORAGE extern __thread MercuryEngine *MR_thread_engine_base; #define MR_set_thread_engine_base(eng) \ do { MR_thread_engine_base = eng; } while (0) #else extern MercuryThreadKey MR_engine_base_key; #define MR_thread_engine_base \ ((MercuryEngine *) MR_GETSPECIFIC(MR_engine_base_key)) #define MR_set_thread_engine_base(eng) \ pthread_setspecific(MR_engine_base_key, eng) #endif #if MR_NUM_REAL_REGS > 0 #define MR_ENGINE_BASE_REGISTER /* ** MR_engine_base is defined in machdeps/{arch}.h */ #else /* MR_NUM_REAL_REGS == 0 */ /* ** MR_maybe_local_thread_engine_base can be redefined to refer to a ** local copy of MR_thread_engine_base. */ #define MR_maybe_local_thread_engine_base MR_thread_engine_base #define MR_engine_base MR_maybe_local_thread_engine_base #define MR_MAYBE_INIT_LOCAL_THREAD_ENGINE_BASE \ MercuryEngine *MR_local_thread_engine_base = MR_thread_engine_base; #endif /* MR_NUM_REAL_REGS == 0 */ #define MR_ENGINE(x) (((MercuryEngine *) MR_engine_base)->x) #define MR_cur_engine() ((MercuryEngine *) MR_engine_base) #define MR_get_engine() ((MercuryEngine *) MR_thread_engine_base) #ifndef MR_HIGHLEVEL_CODE /* ** This points to an array containing MR_num_threads pointers to Mercury engines. ** The first item in the array is the primordial thread. During ** initialisation the array may be a null pointer as may be any pointer ** inside. */ extern MercuryEngine **MR_all_engine_bases; #endif #else /* !MR_THREAD_SAFE */ extern MercuryEngine MR_engine_base; #define MR_ENGINE(x) (MR_engine_base.x) #define MR_cur_engine() (&MR_engine_base) #define MR_get_engine() (&MR_engine_base) #endif /* !MR_THREAD_SAFE */ #ifndef MR_MAYBE_INIT_LOCAL_THREAD_ENGINE_BASE #define MR_MAYBE_INIT_LOCAL_THREAD_ENGINE_BASE #endif #define MR_CONTEXT(x) (MR_ENGINE(MR_eng_context).x) #ifndef MR_CONSERVATIVE_GC #define MR_IF_NOT_CONSERVATIVE_GC(x) x #else #define MR_IF_NOT_CONSERVATIVE_GC(x) #endif #define MR_load_engine_regs(eng) \ do { \ MR_IF_NOT_CONSERVATIVE_GC(MR_hp_word = (MR_Word) (eng)->MR_eng_hp;) \ MR_IF_NOT_CONSERVATIVE_GC(MR_sol_hp = (eng)->MR_eng_sol_hp;) \ MR_IF_NOT_CONSERVATIVE_GC(MR_global_hp = (eng)->MR_eng_global_hp;) \ } while (0) #define MR_save_engine_regs(eng) \ do { \ MR_IF_NOT_CONSERVATIVE_GC((eng)->MR_eng_hp = MR_hp;) \ MR_IF_NOT_CONSERVATIVE_GC((eng)->MR_eng_sol_hp = MR_sol_hp;) \ MR_IF_NOT_CONSERVATIVE_GC((eng)->MR_eng_global_hp = MR_global_hp;) \ } while (0) /* ** Functions for creating/destroying a MercuryEngine. */ extern MercuryEngine *MR_create_engine(void); extern void MR_destroy_engine(MercuryEngine *engine); /* ** Functions for initializing/finalizing a MercuryEngine. ** These are like create/destroy except that they don't allocate/deallocate ** the MercuryEngine structure. */ extern void MR_init_engine(MercuryEngine *engine); extern void MR_finalize_engine(MercuryEngine *engine); /* ** Functions that act on the current Mercury engine. ** See the comments in mercury_engine.c for documentation on MR_call_engine(). */ extern MR_Word *MR_call_engine(MR_Code *entry_point, MR_bool catch_exceptions); extern void MR_terminate_engine(void); extern void MR_dump_prev_locations(void); /*---------------------------------------------------------------------------*/ /* ** Builtin labels that point to some standard code fragments. */ MR_declare_entry(MR_do_redo); MR_declare_entry(MR_do_fail); MR_declare_entry(MR_do_reset_hp_fail); MR_declare_entry(MR_do_reset_framevar0_fail); MR_declare_entry(MR_do_succeed); MR_declare_entry(MR_do_not_reached); MR_declare_entry(MR_exception_handler_do_fail); #endif /* not MERCURY_ENGINE_H */