mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 04:14:06 +00:00
Branches: main Add float registers to the Mercury abstract machine, implemented as an array of MR_Float in the Mercury engine structure. Float registers are only useful if a Mercury `float' is wider than a word (i.e. when using double precision floats on 32-bit platforms) so we let them exist only then. In other cases floats may simply be passed via the regular registers, as before. Currently, higher order calls still require the use of the regular registers for all arguments. As all exported procedures are potentially the target of higher order calls, exported procedures must use only the regular registers for argument passing. This can lead to more (un)boxing than if floats were simply always boxed. Until this is solved, float registers must be enabled explicitly with the developer only option `--use-float-registers'. The other aspect of this change is using two consecutive stack slots to hold a single double variable. Without that, the benefit of passing unboxed floats via dedicated float registers would be largely eroded. compiler/options.m: Add developer option `--use-float-registers'. compiler/handle_options.m: Disable `--use-float-registers' if floats are not wider than words. compiler/make_hlds_passes.m: If `--use-float-registers' is in effect, enable a previous change that allows float constructor arguments to be stored unboxed in structures. compiler/hlds_llds.m: Move `reg_type' here from llds.m and `reg_f' option. Add stack slot width to `stack_slot' type. Add register type and stack slot width to `abs_locn' type. Remember next available float register in `abs_follow_vars'. compiler/hlds_pred.m: Add register type to `arg_loc' type. compiler/llds.m: Add a new kind of lval: double-width stack slots. These are used to hold double-precision floating point values only. Record setting of `--use-float-registers' in exprn_opts. Conform to addition of float registers and double stack slots. compiler/code_info.m: Make predicates take the register type as an argument, where it can no longer be assumed. Remember whether float registers are being used. Remember max float register for calls to MR_trace. Count double width stack slots as two slots. compiler/arg_info.m: Allocate float registers for procedure arguments when appropriate. Delete unused predicates. compiler/var_locn.m: Make predicates working with registers either take the register type as an argument, or handle both register types at once. Select float registers for variables when appropriate. compiler/call_gen.m: Explicitly use regular registers for all higher-order calls, which was implicit before. compiler/pragma_c_gen.m: Use float registers, when available, at the interface between Mercury code and C foreign_procs. compiler/export.m: Whether a float rval needs to be boxed/unboxed when assigned to/from a register depends on the register type. compiler/fact_table.m: Use float registers for arguments to predicates defined by fact tables. compiler/stack_alloc.m: Allocate two consecutive stack slots for float variables when appropriate. compiler/stack_layout.m: Represent double-width stack slots in procedure layout structures. Conform to changes. compiler/store_alloc.m: Allocate float registers (if they exist) for float variables. compiler/use_local_vars.m: Substitute float abstract machine registers with MR_Float local variables. compiler/llds_out_data.m: compiler/llds_out_instr.m: Output float registers and double stack slots. compiler/code_util.m: compiler/follow_vars.m: Count float registers separately from regular registers. compiler/layout.m: compiler/layout_out.m: compiler/trace_gen.m: Remember the max used float register for calls to MR_trace(). compiler/builtin_lib_types.m: Fix incorrect definition of float_type_ctor. compiler/bytecode_gen.m: compiler/continuation_info.m: compiler/disj_gen.m: compiler/dupelim.m: compiler/exprn_aux.m: compiler/global_data.m: compiler/hlds_out_goal.m: compiler/jumpopt.m: compiler/llds_to_x86_64.m: compiler/lookup_switch.m: compiler/opt_debug.m: compiler/opt_util.m: compiler/par_conj_gen.m: compiler/proc_gen.m: compiler/string_switch.m: compiler/tag_switch.m: compiler/tupling.m: compiler/x86_64_regs.m: Conform to changes. runtime/mercury_engine.h: Add an array of fake float "registers" to the Mercury engine structure, when MR_Float is wider than MR_Word. runtime/mercury_regs.h: Document float registers in the Mercury abstract machine. Add macros to access float registers in the Mercury engine. runtime/mercury_stack_layout.h: Add new MR_LongLval cases to represent double-width stack slots. MR_LONG_LVAL_TAGBITS had to be increased to accomodate the new cases, which increases the number of integers in [0, 2^MR_LONG_LVAL_TAGBITS) equal to 0 modulo 4. These are the new MR_LONG_LVAL_TYPE_CONS_n cases. Add max float register field to MR_ExecTrace. runtime/mercury_layout_util.c: runtime/mercury_layout_util.h: Extend MR_copy_regs_to_saved_regs and MR_copy_saved_regs_to_regs for float registers. Understand how to look up new kinds of MR_LongLval: MR_LONG_LVAL_TYPE_F (previously unused), MR_LONG_LVAL_TYPE_DOUBLE_STACKVAR, MR_LONG_LVAL_TYPE_DOUBLE_FRAMEVAR. Conform to the new MR_LONG_LVAL_TYPE_CONS_n cases. runtime/mercury_float.h: Delete redundant #ifdef. runtime/mercury_accurate_gc.c: runtime/mercury_agc_debug.c: Conform to changes (untested). trace/mercury_trace.c: trace/mercury_trace.h: trace/mercury_trace_declarative.c: trace/mercury_trace_external.c: trace/mercury_trace_internal.c: trace/mercury_trace_spy.c: trace/mercury_trace_vars.c: trace/mercury_trace_vars.h: Handle float registers in the trace subsystem. This is mostly a matter of saving/restoring them as with regular registers.
598 lines
24 KiB
C
598 lines
24 KiB
C
/*
|
|
** 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 <setjmp.h>
|
|
|
|
#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 */
|