Cleaned up runtime directory.

Estimated hours taken: 2

Cleaned up runtime directory.

runtime/*.c:
	- Renamed all .c files as mercury_*.c
	  Some have been renamed to make their purpose clearer.
	  	call.mod -> mercury_ho_call.c

runtime/*.h:
	- Moved contents of .h files to mercury_*.h
	- *.h now contain #include mercury_*.h. They be removed later.
	- Updated references to conf.h -> mercury_conf.h

runtime/conf.h.in:
	- Renamed conf.h.in as mercury_conf.h.in.
	  Didn't leave a forwarding header for this one, as conf.h was
	  never part of the repository anyway.

runtime/Mmakefile:
	- Convert lists to one-per-line lists.
	- Add mercury_accurate_gc.h to HDRS.
	- Remove all .mod files
	- Make sure runtime.init uses the ORIG_CS not MOD_CS.
	- Fix the rules for "clean_o" and "clean_mod_c", which used
	  wildcards like "*.o" to remove files.  The one that removed
	  all .c files corresponding with *.mod, instead of using MOD_CS
	  was particularly vicious.
	- Cope with the file renamings.

configure.in:
	- Cope with the file renamings.
This commit is contained in:
Tyson Dowd
1997-11-20 02:04:40 +00:00
parent 860c9ef99a
commit 7ce7d489a2
81 changed files with 4380 additions and 4232 deletions

View File

@@ -44,7 +44,7 @@ clean:
.PHONY: distclean
distclean: clean
cd scripts; for file in *.in; do rm -f `basename $file .in`; done
-rm -f Mmake.common runtime/conf.h bindist/bindist.build_vars
-rm -f Mmake.common runtime/mercury_conf.h bindist/bindist.build_vars
-rm -f config.cache config.status config.log
.PHONY: maintainer-clean

View File

@@ -173,7 +173,7 @@ tar: README INSTALL
cd doc && mmake distclean
-rm -f errs errs2 update.log
-rm -f config.status config.cache config.log configure.log
-rm -f runtime/conf.h
-rm -f runtime/mercury_conf.h
-rm -f Mmake.common
# Package up the mercury directory and the tests directory,
# but with some subdirectories excluded, into a gzipped tar

View File

@@ -20,7 +20,7 @@ dnl MERCURY_MSG(MESSAGE)
define(MERCURY_MSG,
[echo $1 1>&AC_FD_MSG])
#-----------------------------------------------------------------------------#
AC_INIT(runtime/wrapper.mod)
AC_INIT(runtime/mercury_wrapper.c)
#-----------------------------------------------------------------------------#
#
# Ensure that all messages are saved to a file `configure.log' by
@@ -39,7 +39,7 @@ if test "$SUPPRESS_LOG_FILE_RECURSION" != "yes"; then
exit
fi
#-----------------------------------------------------------------------------#
AC_CONFIG_HEADER(runtime/conf.h)
AC_CONFIG_HEADER(runtime/mercury_conf.h)
AC_PREFIX_DEFAULT(/usr/local/mercury-`. ./VERSION; echo $VERSION`)
AC_CANONICAL_HOST
FULLARCH="$host"
@@ -210,7 +210,7 @@ AC_SUBST(CC)
CFLAGS="-O"
# we also need to add the appropriate `-I' options so that the test programs
# can do #include "memory.h"
# can #include various Mercury runtime headers.
CFLAGS="-I runtime -I runtime/machdeps $CFLAGS"
AC_PROG_CPP
AC_C_CROSS
@@ -1079,10 +1079,10 @@ if test $HAVE_ASM_LABELS = 1; then
AC_DEFINE(HAVE_ASM_LABELS)
fi
#-----------------------------------------------------------------------------#
# We need to ensure that runtime/conf.h exists, since some of the
# We need to ensure that runtime/mercury_conf.h exists, since some of the
# programs we attempt to compile below indirectly include it.
test -f runtime/conf.h || {
cat > runtime/conf.h <<EOF
test -f runtime/mercury_conf.h || {
cat > runtime/mercury_conf.h <<EOF
#define WORD_TYPE $WORD_TYPE
EOF
}
@@ -1093,8 +1093,8 @@ if test $mercury_cv_gcc_labels = yes || test $mercury_cv_asm_labels = yes; then
AC_TRY_RUN([
#define USE_GCC_NONLOCAL_GOTOS
#define USE_GCC_GLOBAL_REGISTERS
#include "regs.h"
#include "memory.h"
#include "mercury_regs.h"
#include "mercury_memory.h"
changequote(<<,>>)
Word fake_reg[MAX_FAKE_REG];
changequote([,])
@@ -1154,8 +1154,8 @@ AC_MSG_CHECKING(whether we can use global registers without gcc labels)
AC_CACHE_VAL(mercury_cv_gcc_model_reg,
AC_TRY_RUN([
#define USE_GCC_GLOBAL_REGISTERS
#include "regs.h"
#include "memory.h"
#include "mercury_regs.h"
#include "mercury_memory.h"
changequote(<<,>>)
Word fake_reg[MAX_FAKE_REG];
changequote([,])
@@ -1443,7 +1443,8 @@ case "$host" in
#
# If you *do* use `-fpic', you must also use `-DPIC'.
#
# See runtime/goto.h for the code that handles PIC on SPARCs.
# See runtime/mercury_goto.h for the code that handles PIC
# on SPARCs.
# Note that mixing PIC and non-PIC code is fine on SPARCs
# (though it doesn't work on x86s, due to the use of `ebx'
# in runtime/machdeps/i386_regs.h).
@@ -1551,8 +1552,8 @@ scripts/mmake scripts/mnc scripts/mnl scripts/mnp scripts/c2init
scripts/msc scripts/msl scripts/msp scripts/sicstus_conv
scripts/mkfifo_using_mknod bindist/bindist.build_vars
,
if test "$CONFIG_HEADERS" = "runtime/conf.h"; then
touch runtime/conf.h.date
if test "$CONFIG_HEADERS" = "runtime/mercury_conf.h"; then
touch runtime/mercury_conf.h.date
fi
# conftest.junk is used to avoid a warning if there
# are no files in the list passed to chmod

View File

@@ -22,32 +22,87 @@ MOD2C = $(SCRIPTS_DIR)/mod2c
#-----------------------------------------------------------------------------#
# keep this list in alphabetical order, please
HDRS = calls.h conf.h context.h \
deep_copy.h dlist.h debug.h dummy.h \
engine.h getopt.h goto.h heap.h imp.h init.h label.h \
memory.h mercury_float.h mercury_grade.h \
mercury_string.h mercury_trace.h mercury_trail.h \
mercury_types.h misc.h \
overflow.h prof.h prof_mem.h regorder.h regs.h \
spinlock.h std.h stacks.h \
table.h tags.h timing.h type_info.h wrapper.h \
$(LIBMER_DLL_H)
HDRS = \
mercury_engine.h \
mercury_getopt.h \
mercury_goto.h \
mercury_heap.h \
mercury_imp.h \
mercury_init.h \
mercury_label.h \
mercury_memory.h \
mercury_accurate_gc.h \
mercury_calls.h \
mercury_conf.h \
mercury_context.h \
mercury_debug.h \
mercury_deep_copy.h \
mercury_dummy.h \
mercury_dlist.h \
mercury_float.h \
mercury_string.h \
mercury_trace.h \
mercury_trail.h \
mercury_types.h \
mercury_misc.h \
mercury_overflow.h \
mercury_prof.h \
mercury_prof_mem.h \
mercury_regorder.h \
mercury_regs.h \
mercury_spinlock.h \
mercury_std.h \
mercury_stacks.h \
mercury_table.h \
mercury_tags.h \
mercury_timing.h \
mercury_type_info.h \
mercury_wrapper.h \
$(LIBMER_DLL_H)
# Note that `libmer_globals.h' cannot be part of $(HDR),
# since it depends on libmer_def.a, and $(OBJ) : $(HDR) would create a
# circular dependency.
MACHHDRS = machdeps/no_regs.h machdeps/i386_regs.h \
machdeps/mips_regs.h machdeps/sparc_regs.h \
machdeps/alpha_regs.h machdeps/pa_regs.h \
machdeps/rs6000_regs.h
MODS = engine.mod wrapper.mod call.mod context.mod type_info.mod
MOD_CS = engine.c wrapper.c call.c context.c type_info.c
MACHHDRS = machdeps/no_regs.h \
machdeps/i386_regs.h \
machdeps/mips_regs.h \
machdeps/sparc_regs.h \
machdeps/alpha_regs.h \
machdeps/pa_regs.h \
machdeps/rs6000_regs.h
# XXX .mod support is being removed. This will soon disappear.
MODS =
MOD_CS =
MOD_OS = $(MOD_CS:.c=.o)
ORIG_CS = deep_copy.c dlist.c dummy.c label.c \
memory.c misc.c regs.c table.c timing.c prof.c prof_mem.c \
spinlock.c mercury_float.c mercury_grade.c mercury_trace.c \
mercury_trail.c
# keep this list in alphabetical order, please
ORIG_CS = mercury_context.c \
mercury_deep_copy.c \
mercury_dlist.c \
mercury_dummy.c \
mercury_engine.c \
mercury_float.c \
mercury_grade.c \
mercury_ho_call.c \
mercury_label.c \
mercury_memory.c \
mercury_misc.c \
mercury_prof.c \
mercury_prof_mem.c \
mercury_regs.c \
mercury_spinlock.c \
mercury_table.c \
mercury_timing.c \
mercury_trace.c \
mercury_trail.c \
mercury_type_info.c \
mercury_wrapper.c
ORIG_OS = $(ORIG_CS:.c=.o)
ORIG_OS = $(ORIG_CS:.c=.o)
OBJS = $(MOD_OS) $(ORIG_OS)
PIC_OBJS = $(OBJS:.o=.$(EXT_FOR_PIC_OBJECTS))
@@ -96,8 +151,8 @@ libmer.so: $(PIC_OBJS)
$(LDFLAGS) $(LDLIBS) \
$(SHARED_LIBS)
runtime.init: $(MOD_CS)
cat `vpath_find $(MOD_CS)` | grep '^INIT ' > runtime.init
runtime.init: $(ORIG_CS)
cat `vpath_find $(ORIG_CS)` | grep '^INIT ' > runtime.init
conf.h.date: $(MERCURY_DIR)/config.status conf.h.in
CONFIG_FILES= CONFIG_HEADERS=conf.h $(MERCURY_DIR)/config.status
@@ -161,13 +216,11 @@ clean: clean_o clean_mod_c
.PHONY: clean_o
clean_o:
rm -f *.o *.pic_o
rm -f $(MOD_OS) $(OBJS) $(PIC_OBJS)
.PHONY: clean_mod_c
clean_mod_c:
for file in *.mod; do \
rm -f `basename $$file .mod`.c; \
done
rm -f $(MOD_OS)
realclean:
rm -f libmer.a libmer.so runtime.init

View File

@@ -4,127 +4,5 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* calls.h - definitions for calls and returns */
#include "mercury_calls.h"
#ifndef CALLS_H
#define CALLS_H
#include "regs.h" /* for MR_succip */
#include "goto.h" /* calls are implemented using gotos */
#include "debug.h" /* we need to debug them */
#include "prof.h" /* we need to profile them */
#define noprof_localcall(label, succ_cont) \
do { \
debugcall(LABEL(label), (succ_cont)); \
MR_succip = (succ_cont); \
set_prof_current_proc(LABEL(label)); \
GOTO_LABEL(label); \
} while (0)
/*
** On some systems [basically those using PIC (Position Independent Code)],
** if we're using gcc non-local gotos to jump between functions then
** we need to do ASM_FIXUP_REGS after each return from a procedure call.
*/
#if defined(USE_GCC_NONLOCAL_GOTOS) && defined(NEED_ASM_FIXUP_REGS)
#define noprof_call(proc, succ_cont) \
({ \
__label__ fixup_gp; \
debugcall((proc), (succ_cont)); \
MR_succip = (&&fixup_gp); \
set_prof_current_proc(proc); \
GOTO(proc); \
fixup_gp: \
ASM_FIXUP_REGS \
GOTO(succ_cont); \
})
/* same as above, but with GOTO_LABEL rather than GOTO */
#define noprof_call_localret(proc, succ_cont) \
({ \
__label__ fixup_gp; \
debugcall((proc), (succ_cont)); \
MR_succip = (&&fixup_gp); \
set_prof_current_proc(proc); \
GOTO(proc); \
fixup_gp: \
ASM_FIXUP_REGS \
GOTO_LABEL(succ_cont); \
})
#else
#define noprof_call(proc, succ_cont) \
do { \
debugcall((proc), (succ_cont)); \
MR_succip = (succ_cont); \
set_prof_current_proc(proc); \
GOTO(proc); \
} while (0)
#define noprof_call_localret(proc, succ_cont) \
noprof_call((proc), LABEL(succ_cont))
#endif
#define localcall(label, succ_cont, current_label) \
do { \
debugcall(LABEL(label), (succ_cont)); \
MR_succip = (succ_cont); \
PROFILE(LABEL(label), (current_label)); \
set_prof_current_proc(LABEL(label)); \
GOTO_LABEL(label); \
} while (0)
#define call(proc, succ_cont, current_label) \
do { \
PROFILE((proc), (current_label)); \
noprof_call((proc), (succ_cont)); \
} while (0)
#define call_localret(proc, succ_cont, current_label) \
do { \
PROFILE((proc), (current_label)); \
noprof_call_localret(proc, succ_cont); \
} while (0)
#define call_det_closure(succ_cont, current_label) \
do { \
Declare_entry(do_call_det_closure); \
call(ENTRY(do_call_det_closure), \
(succ_cont), (current_label)); \
} while (0)
#define call_semidet_closure(succ_cont, current_label) \
do { \
Declare_entry(do_call_semidet_closure); \
call(ENTRY(do_call_semidet_closure), \
(succ_cont), (current_label)); \
} while (0)
#define call_nondet_closure(succ_cont, current_label) \
do { \
Declare_entry(do_call_nondet_closure); \
call(ENTRY(do_call_nondet_closure), \
(succ_cont), (current_label)); \
} while (0)
#define localtailcall(label, current_label) \
do { \
debugtailcall(LABEL(label)); \
PROFILE(LABEL(label), (current_label)); \
set_prof_current_proc(LABEL(label)); \
GOTO_LABEL(label); \
} while (0)
#define tailcall(proc, current_label) \
do { \
debugtailcall(proc); \
PROFILE((proc), (current_label)); \
set_prof_current_proc(proc); \
GOTO(proc); \
} while (0)
#define proceed() \
do { \
debugproceed(); \
GOTO(MR_succip); \
} while (0)
#endif /* not CALLS_H */

View File

@@ -1,198 +0,0 @@
/*
** Copyright (C) 1995-1997 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.
*/
/*
** conf.h.in -
** Various configuration parameters, determined automatically by
** the auto-configuration script.
*/
/*
** Note -- this file must not contain any #include statements,
** for reasons explained in imp.h.
*/
#ifndef CONF_H
#define CONF_H
/*
** WORD_TYPE: the base type for the definition of Word.
** This must be a C integral type (e.g. int, long, or long long)
** without any explicit signedness.
** It ought to be the same size as the machine's general-purpose registers.
*/
#undef WORD_TYPE
/*
** LOW_TAG_BITS: an integer, specifying the number of low-order tag bits
** we can use. Normally this is the base-2 log of the word size in bytes.
*/
#undef LOW_TAG_BITS
/*
** BOXED_FLOAT: defined if double precision floats might not fit
** in a Word, and hence must be boxed.
** Note that when bootstrapping from the source distribution,
** we initially build things without BOXED_FLOAT even on machines
** for which sizeof(Float) <= sizeof(Word).
** Conversely if BOXED_FLOAT is undefined, it implies that
** sizeof(Float) <= sizeof(Word).
*/
#undef BOXED_FLOAT
/*
** The following macros are defined iff the corresponding header file
** is available:
**
** HAVE_SYS_SIGINFO we have <sys/siginfo.h>
** HAVE_UCONTEXT we have <ucontext.h>
** HAVE_SYS_UCONTEXT we have <sys/ucontext.h>
** HAVE_ASM_SIGCONTEXT we have <asm/sigcontext.h> (e.g. i386 Linux)
** HAVE_SYS_TIME we have <sys/time.h>
** HAVE_SYS_PARAM we have <sys/param.h>
** HAVE_SYS_WAIT we have <sys/wait.h>
*/
#undef HAVE_SYS_SIGINFO
#undef HAVE_UCONTEXT
#undef HAVE_SYS_UCONTEXT
#undef HAVE_ASM_SIGCONTEXT
#undef HAVE_SYS_TIME
#undef HAVE_SYS_PARAM
#undef HAVE_SYS_WAIT
/*
** The following macros are defined iff the corresponding function or
** system call is available:
**
** HAVE_SYSCONF we have the sysconf() system call.
** HAVE_SIGACTION we have the sigaction() sysstem call.
** HAVE_GETPAGESIZE we have the getpagesize() system call.
** HAVE_MPROTECT we have the mprotect() system call.
** HAVE_MEMALIGN we have the memalign() function.
** HAVE_STRERROR we have the strerror() function.
** HAVE_SETITIMER we have the setitimer() function.
** HAVE_MEMMOVE we have the memmove() function.
*/
#undef HAVE_SYSCONF
#undef HAVE_SIGACTION
#undef HAVE_GETPAGESIZE
#undef HAVE_MEMALIGN
#undef HAVE_MPROTECT
#undef HAVE_STRERROR
#undef HAVE_SETITIMER
#undef HAVE_MEMMOVE
/*
** RETSIGTYPE: the return type of signal handlers.
** Either `int' or `void'.
*/
#undef RETSIGTYPE
/*
** We use mprotect() and signals to catch stack and heap overflows.
** In order to detect such overflows, we need to be able to figure
** out what address we were trying to read from or write to when we
** get a SIGSEGV signal. This is a fairly non-portable thing, so
** it has to be done differently on different systems.
** The following macros specify whether we can do it and if so, how.
**
** HAVE_SIGINFO defined iff we can _somehow_ figure out the
** fault address for SIGSEGVs.
** HAVE_SIGINFO_T defined iff we can figure out the
** fault address for SIGSEGVs using sigaction
** and siginfo_t.
** HAVE_SIGCONTEXT_STRUCT defined iff normal signal handlers are given
** sigcontext_struct arguments that we can use to
** figure out the fault address for SIGSEGVs.
*/
#undef HAVE_SIGINFO
#undef HAVE_SIGINFO_T
#undef HAVE_SIGCONTEXT_STRUCT
/*
** For debugging purposes, if we get a fatal signal, we print out the
** program counter (PC) at which the signal occurred.
**
** PC_ACCESS, PC_ACCESS_GREG: the way to access the saved PC in ucontexts.
**
** If PC_ACCESS_GREG is defined, then PC_ACCESS specifies an index into
** the `gregs' (general registers) array, which is a field of the `ucontext'
** struct. Otherwise, if PC_ACCESS is defined then it is a field name
** in the `ucontext' struct. If PC_ACCESS is not defined, then we don't
** have any way of getting the saved PC.
*/
#undef PC_ACCESS
#undef PC_ACCESS_GREG
/*
** SIGACTION_FIELD: the name of the field in the sigaction struct
** (either sa_handler or sa_sigaction). Defined only if HAVE_SIGACTION
** is defined.
*/
#undef SIGACTION_FIELD
/*
** PARALLEL: defined iff we are configuring for parallel execution.
** (This is work in progress... parallel execution is not yet supported.)
*/
#undef PARALLEL
/*
** The bytecode files represent floats in 64-bit IEEE format.
**
** MR_FLOAT_IS_64_BITS: defined iff the C type `float' is exactly 64 bits.
** MR_DOUBLE_IS_64_BITS: defined iff the C type `double' is exactly 64 bits.
** MR_LONG_DOUBLE_IS_64_BITS: defined iff the C type `long double' is exactly
** 64-bits.
**
** XXX why not just have a single MR_64_BIT_FLOAT_TYPE macro,
** defined to `float', `double', or `long double' as appropriate?
*/
#undef MR_FLOAT_IS_64_BIT
#undef MR_DOUBLE_IS_64_BIT
#undef MR_LONG_DOUBLE_IS_64_BIT
/*
** The following macros specify the ordering of bytes within
** are used by the bytecode compiler and the
** bytecode interpreter when writing/reading floats from/to bytecode files.
**
** MR_BIG_ENDIAN: defined iff the host system is big-endian.
** MR_LITTLE_ENDIAN: defined iff the host system is little-endian.
** (Wierd-endian systems should define neither of these.)
*/
#undef MR_BIG_ENDIAN
#undef MR_LITTLE_ENDIAN
/*
** The following macro specifies whether the non-ANSI, non-POSIX,
** but usually available standard library function `tempnam' is
** available.
*/
#undef IO_HAVE_TEMPNAM
/*
** Which version of Mercury is this? (Taken from the file ../VERSION.)
*/
#define MR_VERSION "unknown"
/*
** What system is this version of Mercury configured for?
*/
#define MR_FULLARCH "unknown"
/*
** Should we build the Mercury libraries as Windows DLLs?
*/
#undef USE_DLLS
/*
** For SPARC systems, does `as' not allow `.type' in inline asm?
** (True for SunOS 4.x.)
*/
#undef MR_CANNOT_GROK_ASM_TYPE_DIRECTIVE
#endif /* CONF_H */

View File

@@ -4,392 +4,5 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** context.h - defines Mercury multithreading stuff.
**
** A Context is like a thread. It contains a detstack, a nondetstack, a trail,
** the various pointers that refer to them, a succip, and a thread-
** resumption continuation. Contexts are initally stored in a free-list.
** When one is running, the Unix process that is executing it has a pointer
** to its context structure `this_context'. When a context suspends, it
** calls `save_context(context_ptr)' which copies the context from the
** various registers and global variables into the structure refered to
** by `context_ptr'. The context contains no rN or fN registers - all
** registers are "context save" (by analogy to caller-save).
**
** When a new context is created information is passed to the new context
** on the stack. The top stackframe of the current context is copied to
** become the first det stackframe in the new process. (XXX this will need
** fixing eventually to include the nondet frame as well.)
**
** Threads can migrate transparently between multiple Unix processes.
** This is implicit since all the state of the thread is allocated in
** shared memory, and all the heaps are also in shared memory.
**
** Each Unix process has its own heap and solutions heap (both allocated
** in shared memory). This makes GC harder, but enables heap allocation
** to be done without locking.
** Each context has a copy of the heap pointer that is taken when it is
** switched out. If the Unix process' heap pointer is the same as the
** copied one when the context is switched back in, then it is safe for
** the context to do heap reclamation on failure.
**
** If PARALLEL is not defined, then everything gets executed within a
** single Unix process. No locking is required. No shared memory is
** required. Since there is only one process, no signalling is needed
** to wake suspended processes.
*/
#ifndef CONTEXT_H
#define CONTEXT_H
#include "regs.h" /* for hp. Must come before system headers. */
#include <sys/types.h> /* for pid_t */
#include "mercury_types.h" /* for Word */
#include "mercury_trail.h" /* for MR_TrailEntry */
#include "memory.h" /* for MemoryZone */
#include "spinlock.h" /* for SpinLock */
#include "goto.h" /* for GOTO() */
/*
** If we have parallelism switched on (PARALLEL is defined),
** then we define how many processes should be used.
** Ultimately this should be configurable through the
** MERCURY_OPTIONS environment variable.
*/
#ifdef PARALLEL
extern unsigned numprocs;
#endif
/*
** The number of context structures initially allocated.
** This allocation does not include the stacks that they
** refer to - only the actual context structures.
** At the moment if we need more than this number of contexts,
** we just die. In the longer term, we need to allocate more.
*/
#define INITIAL_NUM_CONTEXTS 20
/*
** The field names that correspond to virtual machine registers:
** sp, maxfr & curfr
** are prefixed with `context_' so that they don't get replaced
** during macro expansion.
*/
typedef struct CONTEXT Context;
struct CONTEXT {
struct CONTEXT *next;
/*
** if this context is in the free-list `next' will point
** to the next free context. If this context is suspended
** waiting for a variable to become bound, `next' will point to
** the next waiting context. If this context is runnable but not
** currently running then `next' points to the next runnable
** context in the runqueue.
*/
Code *resume;
/*
** a pointer to the code at which execution should resume when
** this context is next scheduled.
*/
Code *context_succip;
/* succip for this context */
MemoryZone *detstack_zone;
/* pointer to the detstack_zone for this context */
Word *context_sp;
/* saved stack pointer for this context */
MemoryZone *nondetstack_zone;
/* pointer to the nondetstack_zone for this context */
Word *context_maxfr;
/* saved maxfr pointer for this context */
Word *context_curfr;
/* saved curfr pointer for this context */
#ifdef MR_USE_TRAIL
MemoryZone *trail_zone;
/* pointer to the MR_trail_zone for this context */
MR_TrailEntry *context_trail_ptr;
/* saved MR_trail_ptr for this context */
MR_ChoicepointId context_ticket_counter;
/* saved MR_ticket_counter for this context */
#endif
Word *context_hp;
/* saved hp for this context */
Word *min_hp_rec;
/*
** this pointer marks the minimum value of hp to which we can
** truncate the heap on backtracking. See comments before the
** set_min_heap_reclamation_point macro (below).
*/
};
/*
** free_context_list is a global linked list of unused context
** structures. If the MemoryZone pointers are not NULL,
** then they point to allocated MemoryZones, which will
** need to be reinitialized, but have space allocated to
** them. (see comments in memory.h about reset_zone())
*/
extern Context **free_context_list_ptr;
/*
** the runqueue is a linked list of contexts that are
** runnable.
*/
extern Context **runqueue_ptr;
/*
** this_context is a pointer to the currently executing
** context. the fields of this_context are not necessarily
** in sync with the real values, since *this_context only
** gets updated when save_context() gets called.
*/
extern Context *this_context;
/* a pointer to a word used for the spinlock on the runqueue */
extern SpinLock *runqueue_lock;
/*
** a pointer to a word used for the spinlock on the free
** context list
*/
extern SpinLock *free_context_list_lock;
/*
** init_processes() forks new process (if necessary), and
** initializes the data-structures for managing the interactions
** between them.
*/
void init_processes(void);
/*
** shutdown_processes() sends a signal to the other processes
** to tell them to shut down. (NOT YET IMPLEMENTED - STUB ONLY.)
*/
void shutdown_processes(void);
/*
** init_process_context() creates a top-level context for
** the original process, and allocates a heap and a solutions-
** heap for each process.
*/
void init_process_context(void);
/*
** new_context() allocates and initializes a new context
** structure.
*/
Context *new_context(void);
/*
** delete_context(ptr) returns the context structure pointed
** to by ptr to the free list, and releases resources as
** necessary.
*/
void delete_context(Context *context);
/*
** flounder() aborts with a runtime error message. It is called if
** the runqueue becomes empty and none of the running processes are
** working - ie the computation has floundered.
*/
void flounder(void);
/*
** procid[N] is the process id of the Nth process.
** procid[my_procnum] == getpid() == my_procid.
*/
extern pid_t *procid;
/*
** procwaiting[N] is true if the process procid[N] is
** suspended because the runqueue was empty when it
** called runnext().
** Although we semantically want bools here, we use
** words to ensure coherency. Since a bool may be
** smaller than a word, storing a bool may be implemented
** in a coherency-breaking manner.
** (Assuming that Words can be read and written in a
** coherent manner is sufficiently important in terms of
** simplifying the synchronization mechanisms, that
** we really need to do so -- or so says Tom, at least.
** I remain unconvinced. -Fergus.)
*/
typedef Word AtomicBool;
extern AtomicBool *procwaiting;
/*
** my_procnum is the number of the current process.
** my_procnum == 0 is the original parent process.
*/
extern int my_procnum;
extern pid_t my_procid;
/* do a context switch */
Declare_entry(do_runnext);
#define runnext() GOTO(ENTRY(do_runnext));
/*
** schedule(Context *cptr, Code *resume):
*/
#define schedule(cptr, resume) do { \
fatal_error("schedule not implemented"); \
} while(0)
/*
** fork_new_context(Code *child, Code *parent, int numslots):
** create a new context to execute the code at `child', and
** copy the topmost `numslots' from the current stackframe.
** The new context gets put on the runqueue, and the current
** context resumes at `parent'.
*/
#define fork_new_context(child, parent, numslots) do { \
Context *fork_new_context_context; \
int fork_new_context_i; \
fork_new_context_context = new_context(); \
for (fork_new_context_i = (numslots) ; \
fork_new_context_i > 0 ; \
fork_new_context_i--) { \
*(fork_new_context_context->context_sp) = \
detstackvar(fork_new_context_i); \
fork_new_context_context->context_sp++; \
} \
fork_new_context_context->resume = (child); \
schedule(fork_new_context_context, (parent)); \
} while (0)
#ifndef CONSERVATIVE_GC
/*
** To figure out the maximum amount of heap we can reclaim on backtracking,
** we compare hp with the context_hp.
**
** If context_hp == NULL then this is the first time this context has been
** scheduled, so the furthest back down the heap we can reclaim is to the
** current value of hp.
**
** If hp > context_hp, another context has allocated data on the heap since
** we were last scheduled, so the furthest back that we can reclaim is to
** the current value of hp, so we set MR_min_hp_rec and the
** field of the same name in our context structure.
**
** If hp < context_hp, then another context has truncated the heap on failure.
** For this to happen, it must be the case that last time we were scheduled,
** that other context was the last one to allocate data on the heap, and we
** did not allocate any heap during that period of execution. That being the
** case, the furthest back to which we can reset the heap is to the current
** value of hp. This is a conservative approximation - it is possible that
** the current value of hp is the same as some previous value that we held,
** and we are now contiguous with our older data, so this algorithm will lead
** to holes in the heap, though GC will reclaim these.
**
** If hp == context_hp then no other process has allocated any heap since we
** were last scheduled, so we can proceed as if we had not stopped, and the
** furthest back that we can backtrack is the same as it was last time we
** were executing.
*/
#define set_min_heap_reclamation_point(ctxt) do { \
if (hp != (ctxt)->context_hp \
|| (ctxt)->context_hp == NULL) \
{ \
MR_min_hp_rec = hp; \
(ctxt)->min_hp_rec = hp;\
} \
else \
{ \
MR_min_hp_rec = (ctxt)->min_hp_rec; \
} \
} while (0)
#define save_hp_in_context(ctxt) do { \
(ctxt)->context_hp = hp; \
(ctxt)->min_hp_rec = MR_min_hp_rec; \
} while (0)
#else
#define set_min_heap_reclamation_point(ctxt) do { } while (0)
#define save_hp_in_context(ctxt) do { } while (0)
#endif
#ifdef MR_USE_TRAIL
#define MR_IF_USE_TRAIL(x) x
#else
#define MR_IF_USE_TRAIL(x)
#endif
#define load_context(cptr) do { \
Context *load_context_c; \
load_context_c = (cptr); \
MR_succip = load_context_c->context_succip; \
detstack_zone = load_context_c->detstack_zone; \
MR_sp = load_context_c->context_sp; \
nondetstack_zone = load_context_c->nondetstack_zone; \
MR_maxfr = load_context_c->context_maxfr; \
MR_curfr = load_context_c->context_curfr; \
MR_IF_USE_TRAIL( \
MR_trail_zone = load_context_c->trail_zone; \
MR_trail_ptr = load_context_c->context_trail_ptr; \
MR_ticket_counter = \
load_context_c->context_ticket_counter; \
) \
set_min_heap_reclamation_point(load_context_c); \
} while (0)
#define save_context(cptr) do { \
Context *save_context_c; \
save_context_c = (cptr); \
save_context_c->context_succip = MR_succip; \
save_context_c->detstack_zone = detstack_zone; \
save_context_c->context_sp = MR_sp; \
save_context_c->nondetstack_zone = nondetstack_zone; \
save_context_c->context_maxfr = MR_maxfr; \
save_context_c->context_curfr = MR_curfr; \
MR_IF_USE_TRAIL( \
save_context_c->trail_zone = MR_trail_zone; \
save_context_c->context_trail_ptr = MR_trail_ptr; \
save_context_c->context_ticket_counter = \
MR_ticket_counter; \
) \
save_hp_in_context(save_context_c); \
} while (0)
/*
** The following two macros join_and_terminate and join_and_continue
** both take a `sync_term' which has the following structure:
** sync_term[SYNC_TERM_LOCK] is a SpinLock
** sync_term[SYNC_TERM_COUNTER] is a counter for the number of
** processes that need to synchronize before the
** parent can proceed.
** sync_term[SYNC_TERM_PARENT] is either NULL or a pointer to the
** context of the parent process. If it is non-null
** then the last process to arrive (the one that
** decrements sync_term[SYNC_TERM_COUNTER] to 0)
** must wake the parent.
** These terms are allocated and manipulated as normal Mercury terms by
** generated Mercury code.
*/
#define SYNC_TERM_LOCK 0
#define SYNC_TERM_COUNTER 1
#define SYNC_TERM_PARENT 2
#define join_and_terminate(sync_term) do { \
fatal_error("join_and_terminate not implemented"); \
} while (0)
#define join_and_continue(sync_term, where_to) do { \
fatal_error("join_and_continue not implemented"); \
} while (0)
#endif
#include "mercury_context.h"

View File

@@ -4,134 +4,5 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* debug.h - definitions for debugging messages */
#ifndef DEBUG_H
#define DEBUG_H
#ifdef DEBUG_ON
#define DEBUG(X) X
#else
#define DEBUG(X)
#endif
#endif
#if defined(SPEED) && !defined(DEBUG_GOTOS)
#define debuggoto(label) ((void)0)
#define debugsreg() ((void)0)
#else
#define debuggoto(label) \
(MR_assert(label), \
IF (gotodebug, (save_transient_registers(), goto_msg(label))))
#define debugsreg() \
IF (sregdebug, (save_transient_registers(), reg_msg()))
#endif
#ifdef SPEED
#define dump_push_msg(msg) ((void)0)
#define dump_pop_msg() ((void)0)
#define debugcr1(val0, hp) ((void)0)
#define debugcr2(val0, val1, hp) ((void)0)
#define debugincrhp(val, hp) ((void)0)
#define debugincrsp(val, sp) ((void)0)
#define debugdecrsp(val, sp) ((void)0)
#define debugpush(val, sp) ((void)0)
#define debugpop(val, sp) ((void)0)
#define debugregs(msg) ((void)0)
#define debugframe(msg) ((void)0)
#define debugmkframe() ((void)0)
#define debugmodframe() ((void)0)
#define debugsucceed() ((void)0)
#define debugsucceeddiscard() ((void)0)
#define debugfail() ((void)0)
#define debugredo() ((void)0)
#define debugcall(proc, succ_cont) ((void)0)
#define debugtailcall(proc) ((void)0)
#define debugproceed() ((void)0)
#define debugmsg0(msg) ((void)0)
#define debugmsg1(msg, arg1) ((void)0)
#define debugmsg2(msg, arg1, arg2) ((void)0)
#define debugmsg3(msg, arg1, arg2, arg3) ((void)0)
#else
#define dump_push_msg(msg) \
(((const char **)dumpstack_zone->min)[dumpindex++] = msg)
#define dump_pop_msg() (--dumpindex)
#define debugcr1(val0, hp) \
IF (heapdebug, (save_transient_registers(), cr1_msg(val0, hp)))
#define debugcr2(val0, val1, hp) \
IF (heapdebug, (save_transient_registers(), cr2_msg(val0, val1, hp)))
#define debugincrhp(val, hp) \
IF (heapdebug, (save_transient_registers(), incr_hp_msg((val), (hp))))
#define debugincrsp(val, sp) \
IF (detstackdebug, (save_transient_registers(), incr_sp_msg((val), (sp))))
#define debugdecrsp(val, sp) \
IF (detstackdebug, (save_transient_registers(), decr_sp_msg((val), (sp))))
#define debugpush(val, sp) \
IF (detstackdebug, (save_transient_registers(), push_msg((val), (sp))))
#define debugpop(val, sp) \
IF (detstackdebug, (save_transient_registers(), pop_msg(val, sp)))
#define debugregs(msg) \
IF (progdebug, (save_transient_registers(), printregs(msg)))
#define debugmkframe() \
IF (nondstackdebug, (save_transient_registers(), mkframe_msg()))
#define debugframe(msg) \
IF (progdebug, (save_transient_registers(), printframe(msg)))
#define debugmodframe() \
IF (nondstackdebug, (save_transient_registers(), modframe_msg()))
#define debugsucceed() \
IF (nondstackdebug, (save_transient_registers(), succeed_msg()))
#define debugsucceeddiscard() \
IF (nondstackdebug, (save_transient_registers(), succeeddiscard_msg()))
#define debugfail() \
IF (nondstackdebug, (save_transient_registers(), fail_msg()))
#define debugredo() \
IF (nondstackdebug, (save_transient_registers(), redo_msg()))
#define debugcall(proc, succ_cont) \
IF (calldebug, (save_transient_registers(), call_msg(proc, succ_cont)))
#define debugtailcall(proc) \
IF (calldebug, (save_transient_registers(), tailcall_msg(proc)))
#define debugproceed() \
IF (calldebug, (save_transient_registers(), proceed_msg()))
#define debugmsg0(msg) \
IF (progdebug, (printf(msg)))
#define debugmsg1(msg, arg1) \
IF (progdebug, (printf(msg, arg1)))
#define debugmsg2(msg, arg1, arg2) \
IF (progdebug, (printf(msg, arg1, arg2)))
#define debugmsg3(msg, arg1, arg2, arg3) \
IF (progdebug, (printf(msg, arg1, arg2, arg3)))
#endif
#include "mercury_debug.h"

View File

@@ -4,62 +4,5 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* deepcopy.h - declares the deep_copy() function. */
#include "mercury_deep_copy.h"
#ifndef DEEP_COPY_H
#define DEEP_COPY_H
#include "mercury_types.h" /* for `Word' */
/* Deep Copy:
**
** Copy a data item, completely.
**
** The copying is done depth first. Any part of the data
** structure that is outside the given upper and lower
** bounds not be copied, instead a reference to the
** original data will be used. For conservative gc grades,
** the entire data structure will be copied, as there is no
** heap.
**
** The caller must provide the type_info describing
** the type of this data structure. It must also
** provide the heap_limit - if no limit is desired,
** NULL or the bottom of the heap may be passed.
** deep_copy returns the address of the new, copied
** data structure.
**
** Deep copy returns the actual data that it copied,
** which may need to be stored on the heap, or put in
** a register or stack slot (depending on what you
** are using deep copy for). This may be a tagged pointer,
** or if the data is just a simple type like a constant
** or integer, it will be the constant or integer itself.
**
** Please note - deep_copy increments the heap pointer,
** however on some platforms (notably, SPARCs) the
** register-windows mean the transient Mercury registers
** may be lost. So before calling deep_copy, call
** save_transient_registers();
**
** deep_copy will use restore_transient_registers()
** to restore the registers and modify the heap pointer, and
** then call save_transient_registers() to save them again.
** (This behaviour may change in future - it may be more
** efficient to just change the saved register - so do not rely on
** it).
**
** After calling deep_copy, be sure to do a
** restore_transient_registers();
** so that the registers are restored.
**
** If writing a C function that calls deep_copy, make sure
** you document that around your function,
** save_transient_registers()/restore_transient_registers()
** need to be used.
*/
Word deep_copy(Word data, Word *type_info, Word *lower_limit,
Word *upper_limit);
#endif /* not DEEP_COPY_H */

View File

@@ -4,68 +4,5 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** dlist.h - defines a doubly-linked list type.
*/
#include "mercury_dlist.h"
#ifndef DLIST_H
#define DLIST_H
/*
** The lists we use are doubly-linked.
** They each have a header node, and we store the length of the list
** in the header node.
*/
typedef struct s_list {
union {
void *l_data;
int l_length;
} l_union;
struct s_list *l_prev;
struct s_list *l_next;
} List;
#define next(ptr) (ptr)->l_next
#define prev(ptr) (ptr)->l_prev
#define ldata(ptr) (ptr)->l_union.l_data
#define llength(list) ((list)->l_union.l_length)
#define first_ptr(list) ((list)->l_next)
#define last_ptr(list) ((list)->l_prev)
#define first(list) ((list)->l_next->l_union.l_data)
#define last(list) ((list)->l_prev->l_union.l_data)
#define makelist(d) list_makelist(d)
#define addhead(l, d) list_addhead(l, d)
#define addtail(l, d) list_addtail(l, d)
#define insert_before(l, w, d) list_insert_before(l, w, d)
#define insert_after(l, w, d) list_insert_after(l, w, d)
#define for_list(p, l) \
for (p = (l? next(l): NULL); p != l && p != NULL; p = next(p))
#define for_2list(p1, p2, l1, l2) \
for ( \
p1 = (l1? next(l1): NULL), p2 = (l2? next(l2): NULL); \
p1 != l1 && p1 != NULL && p2 != l2 && p2 != NULL; \
p1 = next(p1), p2 = next(p2) \
)
#define for_unlist(p, np, l) \
for (p = (l? next(l): NULL), np = (p? next(p): NULL); \
p != l && p != NULL; \
p = np, np = (p? next(p): NULL))
#define end_list(p, l)\
(p == l || p == NULL)
extern List *makelist0(void);
extern List *list_makelist(void *);
extern List *list_addhead(List *, void *);
extern List *list_addtail(List *, void *);
extern List *addlist(List *, List *);
extern List *addndlist(List *, List *);
extern void list_insert_before(List *, List *, void *);
extern void list_insert_after(List *, List *, void *);
extern int length(const List *);
extern void dlist_delete(List *, List *, void (*)(void *));
extern void oldlist(List *, void (*)(void *));
#endif /* not DLIST_H */

View File

@@ -4,19 +4,5 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** File: dummy.h
** Author: fjh
**
** Global variables and functions used purely for the purpose
** of suppressing over-zealous compiler optimizations.
*/
#include "mercury_dummy.h"
#ifndef DUMMY_H
#define DUMMY_H
extern void dummy_function_call(void);
extern void *global_pointer;
extern void *global_pointer_2;
#endif

View File

@@ -4,146 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** engine.h - definitions for the Mercury runtime engine.
**
** For documentation, see the comments in engine.mod.
*/
#ifndef ENGINE_H
#define ENGINE_H
#include <setjmp.h>
#include "std.h" /* for `bool' */
#include "mercury_types.h" /* for `Code *' */
#include "goto.h" /* for `Define_entry()' */
#include "regs.h" /* for NUM_REAL_REGS */
#define PROGFLAG 0
#define GOTOFLAG 1
#define CALLFLAG 2
#define HEAPFLAG 3
#define DETSTACKFLAG 4
#define NONDSTACKFLAG 5
#define FINALFLAG 6
#define MEMFLAG 7
#define SREGFLAG 8
#define TRACEFLAG 9
#define DETAILFLAG 10
#define MAXFLAG 11
/* DETAILFLAG should be the last real flag */
#define progdebug debugflag[PROGFLAG]
#define gotodebug debugflag[GOTOFLAG]
#define calldebug debugflag[CALLFLAG]
#define heapdebug debugflag[HEAPFLAG]
#define detstackdebug debugflag[DETSTACKFLAG]
#define nondstackdebug debugflag[NONDSTACKFLAG]
#define finaldebug debugflag[FINALFLAG]
#define memdebug debugflag[MEMFLAG]
#define sregdebug debugflag[SREGFLAG]
#define tracedebug debugflag[TRACEFLAG]
#define detaildebug debugflag[DETAILFLAG]
/*
** 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_jmp_buf
*/
jmp_buf env; /*
** used by calls to setjmp and longjmp
*/
Word *saved_succip;
Word *saved_sp;
Word *saved_curfr;
Word *saved_maxfr;
MR_IF_USE_TRAIL(Word *saved_trail_ptr;)
MR_IF_USE_TRAIL(Word *saved_ticket_counter;)
#if NUM_REAL_REGS > 0
Word regs[NUM_REAL_REGS];
#endif /* NUM_REAL_REGS > 0 */
} MR_jmp_buf;
/*
** MR_setjmp(MR_jmp_buf *env, longjmp_label)
**
** Save MR_engine_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 r1, 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_jmp_buf; \
save_regs_to_mem((setjmp_env)->regs); \
(setjmp_env)->saved_succip = succip; \
(setjmp_env)->saved_sp = sp; \
(setjmp_env)->saved_curfr = curfr; \
(setjmp_env)->saved_maxfr = 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); \
if (setjmp((setjmp_env)->env)) { \
MR_engine_jmp_buf = (setjmp_env)->mercury_env; \
restore_regs_from_mem((setjmp_env)->regs); \
succip = (setjmp_env)->saved_succip; \
sp = (setjmp_env)->saved_sp; \
curfr = (setjmp_env)->saved_curfr; \
maxfr = (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); \
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)
/*
** engine_jmp_buf should only be referred to in engine.c
** and the MR_setjmp and MR_longjmp macros defined above.
*/
extern jmp_buf *MR_engine_jmp_buf;
extern bool debugflag[];
extern void init_engine(void);
extern void call_engine(Code *entry_point);
extern void terminate_engine(void);
extern void dump_prev_locations(void);
Declare_entry(do_redo);
Declare_entry(do_fail);
Declare_entry(do_reset_hp_fail);
Declare_entry(do_reset_framevar0_fail);
Declare_entry(do_succeed);
Declare_entry(do_not_reached);
#endif /* not ENGINE_H */
#include "mercury_engine.h"

View File

@@ -4,26 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** getopt.h - declares the interface to the system function getopt()
**
** We use this file rather than the system's <getopt.h>
** because different systems have different ideas about
** where the `const's should go on the declaration of getopt().
** Also, some systems might have getopt() but not <getopt.h>.
*/
#ifndef GETOPT_H
#define GETOPT_H
#define GETOPTHUH '?'
#define GETOPTDONE (-1)
extern int getopt(int, char *const*, const char *);
extern char *optarg;
extern int opterr;
extern int optind;
extern int optopt;
#endif /* not GETOPT_H */
#include "mercury_getopt.h"

View File

@@ -4,582 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* goto.h - definitions for the "portable assembler" non-local gotos */
#ifndef GOTO_H
#define GOTO_H
#include "mercury_types.h" /* for `Code *' */
#include "debug.h" /* for debuggoto() */
/*
** Taking the address of a label can inhibit gcc's optimization,
** because it assumes that anything can jump there.
** Therefore we want to do it only if we're debugging,
** or if we need the label address for profiling.
*/
#if defined(SPEED) && !defined(DEBUG_GOTOS)
#define make_label(n, a) /* nothing */
#else
#define make_label(n, a) make_entry(n, a)
#endif
#if defined(SPEED) && !defined(DEBUG_GOTOS) && !defined(PROFILE_CALLS)
#define make_local(n, a) /* nothing */
#else
#define make_local(n, a) make_entry(n, a)
#endif
#if defined(SPEED) && !defined(DEBUG_LABELS) && !defined(DEBUG_GOTOS) \
&& !defined(PROFILE_CALLS)
#define make_entry(n, a) /* nothing */
#else
#define make_entry(n, a) insert_entry(n, a)
#endif
#define paste(a,b) a##b
#define stringify(string) #string
#define entry(label) paste(_entry_,label)
#define skip(label) paste(skip_,label)
#ifdef SPLIT_C_FILES
#define MODULE_STATIC_OR_EXTERN extern
#else
#define MODULE_STATIC_OR_EXTERN static
#endif
/*---------------------------------------------------------------------------*/
/* MACHINE SPECIFIC STUFF REQUIRED FOR NON-LOCAL GOTOS */
#if defined(__alpha__)
/* We need special handling for the "global pointer" (gp) register. */
/*
** When doing a jump, we need to set $27, the "procedure value" register,
** to the address we are jumping to, so that we can use an `ldgp'
** instruction on entry to the procedure to set up the right gp value.
*/
#define ASM_JUMP(address) \
__asm__("bis %0, %0, $27\n\t" \
: : "r"(address) : "$27"); \
goto *(address)
/*
** Explanation:
** Move `address' to register $27,
** jump to `address'.
*/
/*
** on entry to a procedure, we need to load the $gp register
** with the correct value relative to the current address in $27
*/
#define INLINE_ASM_FIXUP_REGS \
" ldgp $gp, 0($27)\n" : : : "memory"
/*
** on fall-thru, we need to skip the ldgp instruction
*/
#define ASM_FALLTHROUGH(label) \
goto skip(label);
#elif defined(__i386__)
/*
** The following hack works around a stack leak on the i386.
** The problem is that gcc pushes function parameters onto
** the stack when calling C functions such as GC_malloc(),
** and only restores the stack pointer in the epilogue.
** With non-local gotos, we jump out of the function without
** executing its epilogue, so the stack pointer never gets
** restored. The result is a memory leak; for example,
** `mc --generate-dependencies mercury_compile' exceeds the
** Slackware Linux default stack space limit of 8M.
**
** GNU C has an option `-fno-defer-pop' which is supposed to
** avoid this sort of thing, but it doesn't work for our
** code using non-local gotos.
**
** We work around this using the dummy assembler code below, which
** pretends to use the stack pointer, forcing gcc to flush any updates
** of the stack pointer immediately, rather than deferring them until
** the function epilogue.
**
** I know this is awful. It wasn't _my_ idea to use non-local gotos ;-)
*/
#define ASM_JUMP(label) \
{ register int stack_pointer __asm__("esp"); \
__asm__("" : : "g"(stack_pointer)); } \
goto *(label)
/*
** That hack above needs to be done for all non-local jumps,
** even if we're not using assembler labels.
*/
#define JUMP(label) ASM_JUMP(label)
/*
** If we're using position-independent code on i386, then we need to
** set up the correct value of the GOT register (ebx).
*/
#if (defined(__pic__) || defined(__PIC__)) && !defined(PIC)
#define PIC 1
#endif
#if PIC
/*
** At each entry point, where we may have been jump to from
** code in a difference C file, we need to set up `ebx'.
** We do this by pushing the IP register using a `call'
** instruction whose target is the very next label.
** We then pop this off the stack into `ebx', and
** then use the value obtained to compute the correct
** value of `ebx' by doing something with _GLOBAL_OFFSET_TABLE_
** (I don't understand the details exactly, this code is
** basically copied from the output of `gcc -fpic -S'.)
** Note that `0f' means the label `0:' following the current
** instruction, and `0b' means the label `0:' before the current
** instruction.
**
** Note: this code clobbers `ebx', which is a callee-save
** register. That means that it is essential that call_engine()
** save `ebx' before entering Mercury code, and restore it
** before returning to C code. However, gcc and/or
** setjmp()/longjmp() will do that for us automatically,
** precisely because it is a callee-save register.
*/
#define INLINE_ASM_FIXUP_REGS \
" call 0f\n" \
"0:\n" \
" popl %%ebx\n" \
" addl $_GLOBAL_OFFSET_TABLE_+[.-0b],%%ebx\n\t" \
: :
#if 0
/*
** The following doesn't seem to be necessary, and
** leaving it out might make gcc generate slightly better code.
*/
/* tell gcc we clobber ebx and memory */ \
: : : "%ebx", "memory"
#endif
/*
** It is safe to fall through into INLINE_ASM_FIXUP_REGS,
** but it might be more efficient to branch past it.
** We should really measure both ways and find out which is
** better... for the moment, we just fall through, since
** that keeps the code smaller.
*/
#if 0
#define ASM_FALLTHROUGH(label) \
goto skip(label);
#endif
#endif /* PIC */
/* For Linux-ELF shared libraries, we need to declare that the type of labels
** is @function (i.e. code, not data), otherwise the dynamic linker seems
** to get confused, and we end up jumping into the data section.
** Hence the `.type' directive below.
*/
#ifdef __ELF__
#define INLINE_ASM_ENTRY_LABEL_TYPE(label) \
" .type _entry_" stringify(label) ",@function\n"
#endif
#elif defined (__sparc)
/*
** If we're using position-independent code on the SPARC, then we need to
** set up the correct value of the GOT register (l7).
*/
#if (defined(__pic__) || defined(__PIC__)) && !defined(PIC)
#define PIC 1
#endif
#if PIC
/*
** At each entry point, where we may have been jump to from
** code in a difference C file, we need to set up `l7'.
** We do this by getting the value the of the IP register using a `call'
** instruction whose target is the very next label; this will
** put the address of the call instruction in register `o7'.
** We then use the value obtained in register `o7' to compute the correct
** value of register `l7' by doing something with _GLOBAL_OFFSET_TABLE_
** (I don't understand the details exactly, this code is
** basically copied from the output of `gcc -fpic -S'.)
** Note that `1f' means the label `1:' following the current
** instruction, and `0b' means the label `0:' before the current
** instruction.
*/
#define INLINE_ASM_FIXUP_REGS \
"0:\n" \
" call 1f\n" \
" nop\n" \
"1:\n" \
" sethi %%hi(_GLOBAL_OFFSET_TABLE_-(0b-.)),%%l7\n" \
" or %%l7,%%lo(_GLOBAL_OFFSET_TABLE_-(0b-.)),%%l7\n" \
" add %%l7,%%o7,%%l7\n" \
/* tell gcc we clobber l7, o7, and memory */ \
: : : "%l7", "%o7", "memory"
/*
** It is safe to fall through into INLINE_ASM_FIXUP_REGS,
** but it might be more efficient to branch past it.
** We should really measure both ways and find out which is
** better... for the moment, we just fall through, since
** that keeps the code smaller.
*/
#if 0
#define ASM_FALLTHROUGH(label) \
goto skip(label);
#endif
#endif /* PIC */
/*
** For Solaris 5.5.1, we need to declare that the type of labels is
** #function (i.e. code, not data), otherwise the dynamic linker seems
** to get confused, and we end up jumping into the data section.
** Hence the `.type' directive below.
*/
#ifndef MR_CANNOT_GROK_ASM_TYPE_DIRECTIVE
#define INLINE_ASM_ENTRY_LABEL_TYPE(label) \
" .type _entry_" stringify(label) ",#function\n"
#endif
#endif
/* for other architectures, these macros have default definitions */
/*
** INLINE_ASM_FIXUP_REGS is used to fix up the value of
** any registers after an ASM_JUMP to an entry point, if necessary.
** It is an assembler string, possibly followed by `: : : <clobbers>'
** where <clobbers> is an indication to gcc of what gets clobbered.
*/
#ifdef INLINE_ASM_FIXUP_REGS
#define ASM_FIXUP_REGS \
__asm__ __volatile__( \
INLINE_ASM_FIXUP_REGS \
);
#define NEED_ASM_FIXUP_REGS
#else
#define ASM_FIXUP_REGS
#define INLINE_ASM_FIXUP_REGS
#undef NEED_ASM_FIXUP_REGS
#endif
/*
** ASM_FALLTHROUGH is executed when falling through into an entry point.
** It may call `goto skip(label)' if it wishes to skip past the
** label and the INLINE_ASM_FIXUP_REGS code.
*/
#ifndef ASM_FALLTHROUGH
#define ASM_FALLTHROUGH(label)
#endif
/*
** INLINE_ASM_GLOBALIZE_LABEL is an assembler string to
** declare an entry label as global. The following definition
** using `.globl' should work with the GNU assembler and
** with most Unix assemblers.
*/
#ifndef INLINE_ASM_GLOBALIZE_LABEL
#define INLINE_ASM_GLOBALIZE_LABEL(label) \
" .globl _entry_" stringify(label) "\n"
#endif
/*
** INLINE_ASM_ENTRY_LABEL_TYPE is an assembler string to
** declare the "type" of a label as function (i.e. code), not data,
** if this is needed.
*/
#ifndef INLINE_ASM_ENTRY_LABEL_TYPE
#define INLINE_ASM_ENTRY_LABEL_TYPE(label)
#endif
/*
** INLINE_ASM_ENTRY_LABEL is an assembler string to
** define an assembler entry label.
*/
#ifndef INLINE_ASM_ENTRY_LABEL
#define INLINE_ASM_ENTRY_LABEL(label) \
"_entry_" stringify(label) ":\n"
#endif
/*
** ASM_JUMP is used to jump to an entry point defined with
** ASM_ENTRY, ASM_STATIC_ENTRY, or ASM_LOCAL_ENTRY.
*/
#ifndef ASM_JUMP
#define ASM_JUMP(address) goto *(address)
#endif
/*---------------------------------------------------------------------------*/
/* The code from here on should be architecture-independent. */
/*---------------------------------------------------------------------------*/
/*
** ASM_ENTRY is used to declare an external entry point
** using a (global) assembler label.
*/
#define ASM_ENTRY(label) \
ASM_FALLTHROUGH(label) \
entry(label): \
__asm__ __volatile__( \
INLINE_ASM_GLOBALIZE_LABEL(label) \
INLINE_ASM_ENTRY_LABEL_TYPE(label) \
INLINE_ASM_ENTRY_LABEL(label) \
INLINE_ASM_FIXUP_REGS \
); \
skip(label): ;
/*
** ASM_STATIC_ENTRY is the same as ASM_ENTRY,
** except that its scope is local to a C file, rather than global.
** Note that even static entry points must do INLINE_ASM_FIXUP_REGS,
** since although there won't be any direct calls to them from another
** C file, their address may be taken and so there may be indirect
** calls.
*/
#define ASM_STATIC_ENTRY(label) \
ASM_FALLTHROUGH(label) \
entry(label): \
__asm__ __volatile__( \
INLINE_ASM_ENTRY_LABEL_TYPE(label) \
INLINE_ASM_ENTRY_LABEL(label) \
INLINE_ASM_FIXUP_REGS \
); \
skip(label): ;
/*
** ASM_LOCAL_ENTRY is the same as ASM_ENTRY,
** except that its scope is local to a BEGIN_MODULE...END_MODULE
** block, rather than being global.
** Note that even local entry points must do INLINE_ASM_FIXUP_REGS, since
** although there won't be any direct calls to them from another
** C file, their address may be taken and so there may be indirect
** calls.
*/
#define ASM_LOCAL_ENTRY(label) \
ASM_FALLTHROUGH(label) \
entry(label): \
ASM_FIXUP_REGS \
skip(label): ;
/*---------------------------------------------------------------------------*/
#if defined(USE_GCC_NONLOCAL_GOTOS)
#ifndef __GNUC__
#error "You must use gcc if you define USE_GCC_NONLOCAL_GOTOS"
#endif
/* Define the type of a module initialization function */
typedef void ModuleFunc(void);
/* The following macro expands to a dummy assembler statement which
** contains no code, but which tells gcc that it uses the specified
** address as an input value. This is used to trick gcc into
** thinking that the address is used, in order to suppress unwanted
** optimizations. (We used to use `volatile_global_pointer =
** address' to suppress optimization, but this way is better because
** it doesn't generate any code.)
*/
#define PRETEND_ADDRESS_IS_USED(address) \
__asm__ __volatile__("" : : "g"(address))
/*
Explanation:
__asm__
__volatile__ don't optimize this asm away
(
"" empty assembler code
: no outputs
: "g" (address) one input value, `address';
"g" means that it can go in any
general-purpose register
)
*/
/* Since we're jumping into and out of the middle of functions,
** we need to make sure that gcc thinks that (1) the function's address
** is used (otherwise it may optimize the whole function away) and
** (2) the `return' statement is reachable (otherwise its dataflow
** analysis for delay slot scheduling may think that global
** register variables which are only assigned to in the function
** cannot be live, when in fact they really are).
** That is what the two occurrences of the PRETEND_ADDRESS_IS_USED
** macro are for.
*/
#define BEGIN_MODULE(module_name) \
MODULE_STATIC_OR_EXTERN void module_name(void); \
MODULE_STATIC_OR_EXTERN void module_name(void) { \
PRETEND_ADDRESS_IS_USED(module_name); \
PRETEND_ADDRESS_IS_USED(&& paste(module_name, _dummy_label)); \
paste(module_name,_dummy_label): \
{
/* initialization code for module goes here */
#define BEGIN_CODE } return; {
/* body of module goes here */
#define END_MODULE } }
#if defined(USE_ASM_LABELS)
#define Declare_entry(label) \
extern void label(void) __asm__("_entry_" stringify(label))
#define Declare_static(label) \
static void label(void) __asm__("_entry_" stringify(label))
#define Define_extern_entry(label) Declare_entry(label)
#define Define_entry(label) \
ASM_ENTRY(label) \
} \
label: \
PRETEND_ADDRESS_IS_USED(&&entry(label)); \
{
#define Define_static(label) \
ASM_STATIC_ENTRY(label) \
} \
label: \
PRETEND_ADDRESS_IS_USED(&&entry(label)); \
{
/*
** The PRETEND_ADDRESS_IS_USED macro is necessary to
** prevent an over-zealous gcc from optimizing away `label'
** and the code that followed.
*/
#define init_entry(label) \
PRETEND_ADDRESS_IS_USED(&&label); \
make_entry(stringify(label), label)
#define ENTRY(label) (&label)
#define STATIC(label) (&label)
#ifndef JUMP
#define JUMP(label) ASM_JUMP(label)
#endif
#else
/* !defined(USE_ASM_LABELS) */
#define Declare_entry(label) extern Code * entry(label)
#define Declare_static(label) static Code * entry(label)
#define Define_extern_entry(label) Code * entry(label)
#define Define_entry(label) \
} \
entry(label): \
label: \
{
#define Define_static(label) \
} \
entry(label): \
label: \
{
#define init_entry(label) \
make_entry(stringify(label), &&label); \
entry(label) = &&label
#define ENTRY(label) (entry(label))
#define STATIC(label) (entry(label))
#ifndef JUMP
#define JUMP(label) goto *(label)
#endif
#endif /* !defined(USE_ASM_LABELS) */
#define Declare_local(label) /* no declaration required */
#define Define_local(label) \
ASM_LOCAL_ENTRY(label) \
} \
label: \
{
#define init_local(label) make_local(stringify(label), &&label)
#define Declare_label(label) /* no declaration required */
#define Define_label(label) Define_local(label)
#define init_label(label) make_label(stringify(label), &&label)
#define LOCAL(label) (&&entry(label))
#define LABEL(label) (&&entry(label))
#define GOTO(label) do { debuggoto(label); JUMP(label); } while(0)
#define GOTO_ENTRY(label) GOTO(ENTRY(label))
#define GOTO_STATIC(label) GOTO(STATIC(label))
#define GOTO_LOCAL(label) GOTO_LABEL(label)
#define GOTO_LABEL(label) do { debuggoto(&&label); goto label; } while(0)
/*
** GOTO_LABEL(label) is the same as GOTO(LABEL(label)) except
** that it may allow gcc to generate slightly better code
*/
#else
/* !defined(USE_GCC_NONLOCAL_GOTOS) */
/* Define the type of a module initialization function */
typedef Code * ModuleFunc(void);
#define BEGIN_MODULE(module_name) \
MODULE_STATIC_OR_EXTERN Code* module_name(void); \
MODULE_STATIC_OR_EXTERN Code* module_name(void) {
#define BEGIN_CODE return 0;
#define END_MODULE }
#define Declare_entry(label) extern void *label(void)
#define Declare_static(label) static void *label(void)
#define Define_extern_entry(label) void *label(void)
#define Define_entry(label) \
GOTO(label); \
} \
Code* label(void) {
#define Define_static(label) \
GOTO(label); \
} \
static Code* label(void) {
#define init_entry(label) make_entry(stringify(label), label)
#define Declare_local(label) static Code *label(void)
#define Define_local(label) \
GOTO(label); \
} \
static Code* label(void) {
#define init_local(label) make_local(stringify(label), label)
#define Declare_label(label) static Code *label(void)
#define Define_label(label) \
GOTO(label); \
} \
static Code* label(void) {
#define init_label(label) make_label(stringify(label), label)
#define ENTRY(label) (label)
#define STATIC(label) (label)
#define LOCAL(label) (label)
#define LABEL(label) (label)
#define GOTO(label) return (label)
/* the call to debuggoto() is in engine.mod */
#define GOTO_ENTRY(label) GOTO(ENTRY(label))
#define GOTO_STATIC(label) GOTO(STATIC(label))
#define GOTO_LOCAL(label) GOTO(LOCAL(label))
#define GOTO_LABEL(label) GOTO(LABEL(label))
#endif /* !defined(USE_GCC_NONLOCAL_GOTOS) */
/* definitions for computed gotos */
#define COMPUTED_GOTO(val, labels) \
{ static Code *jump_table[] = { \
labels \
}; \
GOTO(jump_table[val]); \
}
#define AND , /* used to separate the labels */
#endif /* not GOTO_H */
#include "mercury_goto.h"

View File

@@ -4,189 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* heap.h - definitions for manipulating the Mercury heap */
#ifndef HEAP_H
#define HEAP_H
#include "mercury_types.h" /* for `Word' */
#include "context.h" /* for min_heap_reclamation_point() */
#ifdef CONSERVATIVE_GC
#include "gc.h"
#define tag_incr_hp_n(dest,tag,count) \
((dest) = (Word)mkword((tag), (Word)GC_MALLOC((count) * sizeof(Word))))
#define tag_incr_hp_atomic(dest,tag,count) \
((dest) = (Word)mkword((tag), \
(Word)GC_MALLOC_ATOMIC((count) * sizeof(Word))))
#ifdef INLINE_ALLOC
/*
** The following stuff uses the macros in the `gc_inl.h' header file in the
** Boehm garbage collector. They improve performance a little for
** highly allocation-intensive programs (e.g. the `nrev' benchmark).
** You'll probably need to fool around with the `-I' options to get this
** to work. Also, you must make sure that you compile with the same
** setting for -DSILENT that the boehm_gc directory was compiled with.
**
** We only want to inline allocations if the allocation size is a compile-time
** constant. This should be true for almost all the code that we generate,
** but with GCC we can use the `__builtin_constant_p()' extension to find out.
**
** The inline allocation macros are used only for allocating amounts
** of less than 16 words, to avoid fragmenting memory by creating too
** many distinct free lists. The garbage collector also requires that
** if we're allocating more than one word, we round up to an even number
** of words.
*/
#ifndef __GNUC__
/*
** Without the gcc extensions __builtin_constant_p() and ({...}),
** INLINE_ALLOC would probably be a performance _loss_.
*/
#error "INLINE_ALLOC requires the use of GCC"
#endif
#include "gc_inl.h"
#define tag_incr_hp(dest,tag,count) \
( __builtin_constant_p(count) && (count) < 16 \
? ({ void * temp; \
/* if size > 1, round up to an even number of words */ \
Word num_words = ((count) == 1 ? 1 : 2 * (((count) + 1) / 2)); \
GC_MALLOC_WORDS(temp, num_words); \
(dest) = (Word)mkword((tag), temp); \
}) \
: tag_incr_hp_n((dest),(tag),(count)) \
)
#else /* not INLINE_ALLOC */
#define tag_incr_hp(dest,tag,count) \
tag_incr_hp_n((dest),(tag),(count))
#endif /* not INLINE_ALLOC */
#define mark_hp(dest) ((void)0)
#define restore_hp(src) ((void)0)
/* we use `hp' as a convenient temporary here */
#define hp_alloc(count) (incr_hp(MR_hp,(count)), MR_hp += (count), (void)0)
#define hp_alloc_atomic(count) \
(incr_hp_atomic(MR_hp,(count)), MR_hp += (count), (void)0)
#else /* not CONSERVATIVE_GC */
#define tag_incr_hp(dest,tag,count) ( \
(dest) = (Word)mkword(tag, (Word)MR_hp), \
debugincrhp(count, MR_hp), \
MR_hp += (count), \
heap_overflow_check(), \
(void)0 \
)
#define tag_incr_hp_atomic(dest,tag,count) tag_incr_hp((dest),(tag),(count))
#define mark_hp(dest) ( \
(dest) = (Word)MR_hp, \
(void)0 \
)
/*
** When restoring hp, we must make sure that we don't truncate the heap
** further than it is safe to. We can only truncate it as far as
** min_heap_reclamation_point. See the comments in context.h next to
** the set_min_heap_reclamation_point() macro.
*/
#define restore_hp(src) ( \
LVALUE_CAST(Word,MR_hp) = \
( (Word) MR_min_hp_rec < (src) ? \
(src) : (Word) MR_min_hp_rec ), \
(void)0 \
)
#define hp_alloc(count) incr_hp(hp,count)
#define hp_alloc_atomic(count) incr_hp_atomic(count)
#endif /* not CONSERVATIVE_GC */
#define incr_hp(dest,count) tag_incr_hp((dest),mktag(0),(count))
#define incr_hp_atomic(dest,count) \
tag_incr_hp_atomic((dest),mktag(0),(count))
/*
** Note that gcc optimizes `hp += 2; return hp - 2;'
** to `tmp = hp; hp += 2; return tmp;', so we don't need to use
** gcc's expression statements here
*/
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create1(w1) ( \
hp_alloc(1), \
MR_hp[-1] = (Word) (w1), \
debugcr1(MR_hp[-1], MR_hp), \
/* return */ (Word) (MR_hp - 1) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create2(w1, w2) ( \
hp_alloc(2), \
MR_hp[-2] = (Word) (w1), \
MR_hp[-1] = (Word) (w2), \
debugcr2(MR_hp[-2], MR_hp[-1], MR_hp), \
/* return */ (Word) (MR_hp - 2) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create3(w1, w2, w3) ( \
hp_alloc(3), \
MR_hp[-3] = (Word) (w1), \
MR_hp[-2] = (Word) (w2), \
MR_hp[-1] = (Word) (w3), \
/* return */ (Word) (MR_hp - 3) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create2_bf(w1) ( \
MR_hp = MR_hp + 2, \
MR_hp[-2] = (Word) (w1), \
heap_overflow_check(), \
/* return */ (Word) (MR_hp - 2) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create2_fb(w2) ( \
MR_hp = MR_hp + 2, \
MR_hp[-1] = (Word) (w2), \
heap_overflow_check(), \
/* return */ (Word) (MR_hp - 2) \
)
/*
** Indended for use in handwritten C code where the Mercury registers
** may have been clobbered due to C function calls (eg, on the SPARC due
** to sliding register windows).
** Remember to save_transient_registers() before calls to such code, and
** restore_transient_registers() after.
*/
#define incr_saved_hp(A,B) do { \
restore_transient_registers(); \
incr_hp((A), (B)); \
save_transient_registers(); \
} while (0)
#define incr_saved_hp_atomic(A,B) do { \
restore_transient_registers(); \
incr_hp_atomic((A), (B)); \
save_transient_registers(); \
} while (0)
#endif /* not HEAP_H */
#include "mercury_heap.h"

View File

@@ -4,65 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** imp.h - defines the interface to the Mercury abstract machine.
**
** IMPORTANT: this must be the *first* header file that is #included.
** It must come before any system header files. This is because on some
** systems, the system header files include inline functions, and this
** causes problems when using global register variables, as gcc requires
** global register variable declarations to precede any function definitions.
**
** This file just #includes most of the other Mercury runtime header files.
*/
#ifndef IMP_H
#define IMP_H
/*
** The #include of "conf.h" must come before the `#ifdef USE_DLLS',
** because conf.h defines the USE_DLLS macro.
*/
#include "conf.h"
/*
** The following must come before any definitions of global variables.
** This is necessary to support DLLs on Windows.
*/
#ifdef USE_DLLS
#include "libmer_dll.h"
#endif
#include "regs.h" /* must come before system headers */
#include "std.h"
#include "mercury_types.h"
#include "mercury_string.h"
#include "mercury_float.h"
#include "tags.h"
#include "goto.h"
#include "calls.h"
#include "engine.h"
#include "memory.h"
#include "heap.h"
#include "stacks.h"
#include "overflow.h"
#include "label.h"
#include "wrapper.h"
#include "context.h"
#include "type_info.h"
#ifdef MR_USE_TRAIL
#include "mercury_trail.h"
#endif
#include "debug.h"
#include "prof.h"
#include "misc.h"
#include "mercury_grade.h"
#endif /* not IMP_H */
#include "mercury_imp.h"

View File

@@ -4,99 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** init.h - this file declares stuff defined in the automatically generated
** *_init.c files. This is also the interface used by C code that
** wishes to interface to Mercury.
**
** It also declares some stuff that is used in the automatically
** generate *_init.c files.
*/
#ifndef INIT_H
#define INIT_H
/*
** The following must come before any definitions of global variables.
** This is necessary to support DLLs on Windows.
*/
#include "conf.h" /* for USE_DLLS */
#if USE_DLLS
#include "libmer_dll.h"
#endif
/*---------------------------------------------------------------------------*/
/*
** This part is the interface that should be used by C programs that wish
** to interface to Mercury.
*/
/*
** mercury_main() is defined in the <module>_init.c file.
** It calls mercury_init(), mercury_call_main(), and then mercury_terminate().
*/
extern int mercury_main(int argc, char **argv);
/*
** mercury_init() is defined in the <module>_init.c file.
**
** The `argc' and `argv' parameters are as for main() in C.
** The `stack_bottom' parameter should be the address of a variable
** on the C stack. The conservative garbage collector treats that
** address as the start of the stack, so anything older than that
** address won't get scanned; don't store pointers to GC'ed memory
** in local variables that are older than that.
**
** mercury_init() just does some stuff to initialize the garbage
** collector, sets some global variables, and then calls
** mercury_runtime_init().
*/
extern void mercury_init(int argc, char **argv, char *stack_bottom);
/*
** mercury_call_main() is defined in the <module>_init.c file.
** It just calls mercury_runtime_main(), which calls main/2
** in the Mercury program.
*/
extern void mercury_call_main(void);
/*
** mercury_terminate() is defined in the <module>_init.c file.
** It just calls mercury_runtime_terminate(), which performs
** any necessary cleanup, and then returns the appropriate
** exit status as set by io__set_exit_status.
*/
extern int mercury_terminate(void);
/*---------------------------------------------------------------------------*/
/*
** This part defines things which are used by the automatically
** generated *_init.c file. These should not be used (directly)
** by C programs that wish to interface to Mercury.
*/
#include "goto.h" /* for Declare_entry */
#include "mercury_types.h" /* for `Word' */
#include "wrapper.h" /* for do_init_modules,
mercury_runtime_init(),
mercury_runtime_main(),
mercury_runtime_terminate(),
etc. */
#ifdef CONSERVATIVE_GC
#include "gc.h"
#endif
/*
** mercury_main() takes the address of the following predicates/functions,
** which are defined elsewhere.
*/
Declare_entry(mercury__main_2_0); /* in the user's program */
extern void mercury_init_io(void); /* in the Mercury library */
extern void ML_io_init_state(void); /* in the Mercury library */
extern void ML_io_finalize_state(void); /* in the Mercury library */
#endif /* not INIT_H */
/*---------------------------------------------------------------------------*/
#include "mercury_init.h"

View File

@@ -4,30 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** label.h defines the interface to the label table, which is a pair of
** hash tables mapping from procedure names to addresses and vice versa.
*/
#ifndef LABEL_H
#define LABEL_H
#include "mercury_types.h" /* for `Code *' */
#include "dlist.h" /* for `List' */
typedef struct s_label {
const char *e_name; /* name of the procedure */
Code *e_addr; /* address of the code */
} Label;
extern void do_init_entries(void);
extern Label *insert_entry(const char *name, Code *addr);
extern Label *lookup_label_name(const char *name);
extern Label *lookup_label_addr(const Code *addr);
extern List *get_all_labels(void);
extern int entry_table_size;
/* expected number of entries in the table */
/* we allocate 8 bytes per entry */
#endif /* not LABEL_H */
#include "mercury_label.h"

View File

@@ -4,231 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** memory.h - general memory-allocation related stuff for the Mercury runtime.
**
** This defines the different memory areas used by the Mercury runtime,
** including the det & nondet stacks, the heap (and solutions heap),
** and the fake_reg array for holding Mercury virtual registers.
** It also provides interfaces for constructing new memory zones,
** and for allocating (possibly shared) memory.
*/
#ifndef MEMORY_H
#define MEMORY_H
#include "regs.h" /* for NUM_REAL_REGS */
#include <stdlib.h> /* for size_t */
#include "mercury_types.h" /* for Word */
#include "std.h" /* for bool */
/* these cannot be changed without lots of modifications elsewhere */
#define MAX_REAL_REG 32 /* r1 .. r32 */
#define NUM_SPECIAL_REG 5 /* succip, sp, hp, maxfr, curfr */
/* this can be changed at will, including by -D options to the C compiler */
#ifndef MAX_VIRTUAL_REG
#define MAX_VIRTUAL_REG 1024
#endif
/* allocate enough fake_regs to hold both the special regs */
/* and all the virtual registers */
#define MAX_FAKE_REG (NUM_SPECIAL_REG + MAX_VIRTUAL_REG)
/* mr0 .. mr36, mr(37) ... mr(1028) */
/* reserve MAX_FAKE_REG virtual regs, numbered from 0 to MAX_FAKE_REG-1 */
extern Word fake_reg[MAX_FAKE_REG];
/* used to lookup the fake_reg for a given real reg */
extern Word virtual_reg_map[MAX_REAL_REG];
/* used for counting register usage */
extern unsigned long num_uses[MAX_RN];
/*
** The Mercury runtime uses a number of memory areas or *zones*. These
** hold the detstack, the nondetstack, the heap, and potentially other
** areas such as a trail, a "solutions"-heap, and so on.
** These memory areas are each represented by a structure that contains
** the following fields:
** name - a string constant used to name the allocated area
** id - an integer which together with the name should uniquely
** identify the allocated area.
** bottom - the address of the bottom of the allocated area
** (should be on a page boundary)
** top - the address one word past the top of the allocated area
** (should be on a page boundary)
** min - the address of the lowest part of the allocated that
** will be used. This may be different to `bottom'
** so that the use of different memory zones doesn't
** beat the cache.
** max - the highest address in this memory area that has been
** used so far. This is only defined in debugging grades.
** hardmax - the address of the bottom of the last page of the allocated
** area. This is one higher than the highest address that
** can be used in this zone. We never unprotect the
** last page of a zone so that we retain protection
** against overrunning the end of the zone. This is
** obviously only available on platforms that have
** mprotect.
** (should be on a page boundary)
** redzone - the address of the start of the region that has been
** mprotected as a redzone. Since without SIGINFO
** it is not possible [portably] to figure out
** where the fault occured, redzone is only available
** on platforms that have both mprotect and SIGINFO.
** (should be on a page boundary)
** handler - the address of a function to handle accesses in the
** redzone of this allocated area. This is only
** specified if mprotect and SIGINFO are available.
*/
typedef struct MEMORY_ZONE MemoryZone;
typedef bool ZoneHandler(Word *addr, struct MEMORY_ZONE *zone, void *context);
struct MEMORY_ZONE {
struct MEMORY_ZONE *next; /* the memory zones are organized as a
** linked list of free zones and linked
** list of used zones. The next field
** is NULL or a pointer to the next memory
** zone in the list.
*/
const char *name; /* name identifier */
int id; /* number */
Word *bottom; /* beginning of the allocated area */
Word *top; /* end of the allocated area */
Word *min; /* lowest word of the area to be used */
#ifndef SPEED
Word *max; /* highest word of the area to be used */
#endif
#ifdef HAVE_MPROTECT
Word *redzone_base; /* beginning of the original redzone */
Word *redzone; /* beginning of the current redzone */
Word *hardmax; /* last page of the zone which can't be
unprotected */
#ifdef HAVE_SIGINFO
ZoneHandler *handler; /* handler for page faults in the redzone */
#endif /* HAVE_SIGINFO */
#endif /* HAVE_MPROTECT */
};
#define MAX_ZONES 16
extern MemoryZone *zone_table;
/* A linked list of all the unused zones */
extern MemoryZone *free_memory_zones;
/* A linked list of all the used zones */
extern MemoryZone *used_memory_zones;
extern MemoryZone *detstack_zone;
extern MemoryZone *nondetstack_zone;
#ifndef CONSERVATIVE_GC
extern MemoryZone *heap_zone;
extern MemoryZone *solutions_heap_zone;
#endif
#ifndef SPEED
extern MemoryZone *dumpstack_zone;
extern int dumpindex;
#endif
/*
** create_zone(Name, Id, Size, Offset, RedZoneSize, FaultHandler)
** allocates a new memory zone with name Name, and number Id, size
** Size (in bytes - which gets rounded up to the nearest multiple of
** the page size), an offset Offset from the page boundary at which
** to start using the memory region (used to help avoid beating the cache),
** the amount Redzone of memory (in bytes) to be protected as a redzone
** (must be less than Size), and the address of a function to handle
** memory references in the redzone.
** If it fails to allocate or protect the zone, then it exits.
** If mprotect or SIGINFO are unavailable, then the last two arguments
** are ignored.
*/
MemoryZone *create_zone(const char *name, int id,
size_t size, size_t offset, size_t redsize,
ZoneHandler *handler);
/*
** construct_zone(Name, Id, Base, Size, Offset, RedZoneSize, FaultHandler)
** has the same behaviour as create_zone, except instread of allocating
** the memory, it takes a pointer to a region of memory that must be at
** least Size bytes, or if HAVE_MPROTECT is defined, then it must be at
** least Size + unit[*] bytes.
** If it fails to protect the redzone then it exits
** If mprotect or SIGINFO are unavailable, then the last two arguments
** are ignored.
**
** [*] unit is a global variable containing the page size in bytes
*/
MemoryZone *construct_zone(const char *name, int Id, Word *base,
size_t size, size_t offset, size_t redsize,
ZoneHandler *handler);
/*
** reset_zone(Zone) resets the redzone on the given MemoryZone to the
** original zone specified in the call to {create,construct}_zone() if
** HAVE_MPROTECT and HAVE_SIGINFO. If either HAVE_MPROTECT or HAVE_SIGINFO
** are not defined, it does nothing.
*/
void reset_zone(MemoryZone *zone);
/*
** default_handler is a function that can be passed to create_zone to
** unprotect enough of the redzone to allow the access to succeed, or
** fail if there is no space left in the zone.
*/
ZoneHandler default_handler;
/*
** null_handler is a function that can be passed to create_zone which always
** fails.
*/
ZoneHandler null_handler;
/* for these functions, see the comments in memory.c and engine.mod */
extern void init_memory(void);
extern void init_heap(void);
extern void debug_memory(void);
/*
** next_offset() returns sucessive offsets across the primary cache. Useful
** when calling {create,construct}_zone().
*/
extern size_t next_offset(void);
/*
** allocate_bytes() allocates the given number of bytes.
**
** allocate_object(type) allocates space for an object of the specified type.
**
** allocate_array(type, num) allocates space for an array of objects of the
** specified type.
**
** If shared memory is being used, these allocation routines will allocate
** in shared memory.
*/
extern void *allocate_bytes(size_t numbytes);
#define allocate_object(type) \
((type *)allocate_bytes(sizeof(type)))
#define allocate_array(type, num) \
((type *)allocate_bytes((num) * sizeof(type)))
/*
** deallocate_memory() deallocates the memory allocated by one of the
** allocate_* functions.
*/
void deallocate_memory(void *);
#endif /* not MEMORY_H */
#include "mercury_memory.h"

130
runtime/mercury_calls.h Normal file
View File

@@ -0,0 +1,130 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* calls.h - definitions for calls and returns */
#ifndef CALLS_H
#define CALLS_H
#include "regs.h" /* for MR_succip */
#include "goto.h" /* calls are implemented using gotos */
#include "debug.h" /* we need to debug them */
#include "prof.h" /* we need to profile them */
#define noprof_localcall(label, succ_cont) \
do { \
debugcall(LABEL(label), (succ_cont)); \
MR_succip = (succ_cont); \
set_prof_current_proc(LABEL(label)); \
GOTO_LABEL(label); \
} while (0)
/*
** On some systems [basically those using PIC (Position Independent Code)],
** if we're using gcc non-local gotos to jump between functions then
** we need to do ASM_FIXUP_REGS after each return from a procedure call.
*/
#if defined(USE_GCC_NONLOCAL_GOTOS) && defined(NEED_ASM_FIXUP_REGS)
#define noprof_call(proc, succ_cont) \
({ \
__label__ fixup_gp; \
debugcall((proc), (succ_cont)); \
MR_succip = (&&fixup_gp); \
set_prof_current_proc(proc); \
GOTO(proc); \
fixup_gp: \
ASM_FIXUP_REGS \
GOTO(succ_cont); \
})
/* same as above, but with GOTO_LABEL rather than GOTO */
#define noprof_call_localret(proc, succ_cont) \
({ \
__label__ fixup_gp; \
debugcall((proc), (succ_cont)); \
MR_succip = (&&fixup_gp); \
set_prof_current_proc(proc); \
GOTO(proc); \
fixup_gp: \
ASM_FIXUP_REGS \
GOTO_LABEL(succ_cont); \
})
#else
#define noprof_call(proc, succ_cont) \
do { \
debugcall((proc), (succ_cont)); \
MR_succip = (succ_cont); \
set_prof_current_proc(proc); \
GOTO(proc); \
} while (0)
#define noprof_call_localret(proc, succ_cont) \
noprof_call((proc), LABEL(succ_cont))
#endif
#define localcall(label, succ_cont, current_label) \
do { \
debugcall(LABEL(label), (succ_cont)); \
MR_succip = (succ_cont); \
PROFILE(LABEL(label), (current_label)); \
set_prof_current_proc(LABEL(label)); \
GOTO_LABEL(label); \
} while (0)
#define call(proc, succ_cont, current_label) \
do { \
PROFILE((proc), (current_label)); \
noprof_call((proc), (succ_cont)); \
} while (0)
#define call_localret(proc, succ_cont, current_label) \
do { \
PROFILE((proc), (current_label)); \
noprof_call_localret(proc, succ_cont); \
} while (0)
#define call_det_closure(succ_cont, current_label) \
do { \
Declare_entry(do_call_det_closure); \
call(ENTRY(do_call_det_closure), \
(succ_cont), (current_label)); \
} while (0)
#define call_semidet_closure(succ_cont, current_label) \
do { \
Declare_entry(do_call_semidet_closure); \
call(ENTRY(do_call_semidet_closure), \
(succ_cont), (current_label)); \
} while (0)
#define call_nondet_closure(succ_cont, current_label) \
do { \
Declare_entry(do_call_nondet_closure); \
call(ENTRY(do_call_nondet_closure), \
(succ_cont), (current_label)); \
} while (0)
#define localtailcall(label, current_label) \
do { \
debugtailcall(LABEL(label)); \
PROFILE(LABEL(label), (current_label)); \
set_prof_current_proc(LABEL(label)); \
GOTO_LABEL(label); \
} while (0)
#define tailcall(proc, current_label) \
do { \
debugtailcall(proc); \
PROFILE((proc), (current_label)); \
set_prof_current_proc(proc); \
GOTO(proc); \
} while (0)
#define proceed() \
do { \
debugproceed(); \
GOTO(MR_succip); \
} while (0)
#endif /* not CALLS_H */

View File

@@ -1,4 +1,8 @@
/*
INIT mercury_sys_init_context
ENDINIT
*/
/*
** Copyright (C) 1995-1997 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.
@@ -6,7 +10,7 @@
/* context.mod - handles multithreading stuff. */
#include "imp.h"
#include "mercury_imp.h"
#include <stdio.h>
#include <unistd.h> /* for getpid() and fork() */
@@ -14,8 +18,8 @@
#include <signal.h>
#endif
#include "context.h"
#include "engine.h" /* for `memdebug' */
#include "mercury_context.h"
#include "mercury_engine.h" /* for `memdebug' */
Context *this_context;
static Context *free_context_list = NULL;
@@ -108,3 +112,6 @@ flounder(void)
fatal_error("computation floundered");
}
void mercury_sys_init_context(void); /* suppress gcc warning */
void mercury_sys_init_context(void) {
}

395
runtime/mercury_context.h Normal file
View File

@@ -0,0 +1,395 @@
/*
** Copyright (C) 1997 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.
*/
/*
** context.h - defines Mercury multithreading stuff.
**
** A Context is like a thread. It contains a detstack, a nondetstack, a trail,
** the various pointers that refer to them, a succip, and a thread-
** resumption continuation. Contexts are initally stored in a free-list.
** When one is running, the Unix process that is executing it has a pointer
** to its context structure `this_context'. When a context suspends, it
** calls `save_context(context_ptr)' which copies the context from the
** various registers and global variables into the structure refered to
** by `context_ptr'. The context contains no rN or fN registers - all
** registers are "context save" (by analogy to caller-save).
**
** When a new context is created information is passed to the new context
** on the stack. The top stackframe of the current context is copied to
** become the first det stackframe in the new process. (XXX this will need
** fixing eventually to include the nondet frame as well.)
**
** Threads can migrate transparently between multiple Unix processes.
** This is implicit since all the state of the thread is allocated in
** shared memory, and all the heaps are also in shared memory.
**
** Each Unix process has its own heap and solutions heap (both allocated
** in shared memory). This makes GC harder, but enables heap allocation
** to be done without locking.
** Each context has a copy of the heap pointer that is taken when it is
** switched out. If the Unix process' heap pointer is the same as the
** copied one when the context is switched back in, then it is safe for
** the context to do heap reclamation on failure.
**
** If PARALLEL is not defined, then everything gets executed within a
** single Unix process. No locking is required. No shared memory is
** required. Since there is only one process, no signalling is needed
** to wake suspended processes.
*/
#ifndef CONTEXT_H
#define CONTEXT_H
#include "regs.h" /* for hp. Must come before system headers. */
#include <sys/types.h> /* for pid_t */
#include "mercury_types.h" /* for Word */
#include "mercury_trail.h" /* for MR_TrailEntry */
#include "memory.h" /* for MemoryZone */
#include "spinlock.h" /* for SpinLock */
#include "goto.h" /* for GOTO() */
/*
** If we have parallelism switched on (PARALLEL is defined),
** then we define how many processes should be used.
** Ultimately this should be configurable through the
** MERCURY_OPTIONS environment variable.
*/
#ifdef PARALLEL
extern unsigned numprocs;
#endif
/*
** The number of context structures initially allocated.
** This allocation does not include the stacks that they
** refer to - only the actual context structures.
** At the moment if we need more than this number of contexts,
** we just die. In the longer term, we need to allocate more.
*/
#define INITIAL_NUM_CONTEXTS 20
/*
** The field names that correspond to virtual machine registers:
** sp, maxfr & curfr
** are prefixed with `context_' so that they don't get replaced
** during macro expansion.
*/
typedef struct CONTEXT Context;
struct CONTEXT {
struct CONTEXT *next;
/*
** if this context is in the free-list `next' will point
** to the next free context. If this context is suspended
** waiting for a variable to become bound, `next' will point to
** the next waiting context. If this context is runnable but not
** currently running then `next' points to the next runnable
** context in the runqueue.
*/
Code *resume;
/*
** a pointer to the code at which execution should resume when
** this context is next scheduled.
*/
Code *context_succip;
/* succip for this context */
MemoryZone *detstack_zone;
/* pointer to the detstack_zone for this context */
Word *context_sp;
/* saved stack pointer for this context */
MemoryZone *nondetstack_zone;
/* pointer to the nondetstack_zone for this context */
Word *context_maxfr;
/* saved maxfr pointer for this context */
Word *context_curfr;
/* saved curfr pointer for this context */
#ifdef MR_USE_TRAIL
MemoryZone *trail_zone;
/* pointer to the MR_trail_zone for this context */
MR_TrailEntry *context_trail_ptr;
/* saved MR_trail_ptr for this context */
MR_ChoicepointId context_ticket_counter;
/* saved MR_ticket_counter for this context */
#endif
Word *context_hp;
/* saved hp for this context */
Word *min_hp_rec;
/*
** this pointer marks the minimum value of hp to which we can
** truncate the heap on backtracking. See comments before the
** set_min_heap_reclamation_point macro (below).
*/
};
/*
** free_context_list is a global linked list of unused context
** structures. If the MemoryZone pointers are not NULL,
** then they point to allocated MemoryZones, which will
** need to be reinitialized, but have space allocated to
** them. (see comments in memory.h about reset_zone())
*/
extern Context **free_context_list_ptr;
/*
** the runqueue is a linked list of contexts that are
** runnable.
*/
extern Context **runqueue_ptr;
/*
** this_context is a pointer to the currently executing
** context. the fields of this_context are not necessarily
** in sync with the real values, since *this_context only
** gets updated when save_context() gets called.
*/
extern Context *this_context;
/* a pointer to a word used for the spinlock on the runqueue */
extern SpinLock *runqueue_lock;
/*
** a pointer to a word used for the spinlock on the free
** context list
*/
extern SpinLock *free_context_list_lock;
/*
** init_processes() forks new process (if necessary), and
** initializes the data-structures for managing the interactions
** between them.
*/
void init_processes(void);
/*
** shutdown_processes() sends a signal to the other processes
** to tell them to shut down. (NOT YET IMPLEMENTED - STUB ONLY.)
*/
void shutdown_processes(void);
/*
** init_process_context() creates a top-level context for
** the original process, and allocates a heap and a solutions-
** heap for each process.
*/
void init_process_context(void);
/*
** new_context() allocates and initializes a new context
** structure.
*/
Context *new_context(void);
/*
** delete_context(ptr) returns the context structure pointed
** to by ptr to the free list, and releases resources as
** necessary.
*/
void delete_context(Context *context);
/*
** flounder() aborts with a runtime error message. It is called if
** the runqueue becomes empty and none of the running processes are
** working - ie the computation has floundered.
*/
void flounder(void);
/*
** procid[N] is the process id of the Nth process.
** procid[my_procnum] == getpid() == my_procid.
*/
extern pid_t *procid;
/*
** procwaiting[N] is true if the process procid[N] is
** suspended because the runqueue was empty when it
** called runnext().
** Although we semantically want bools here, we use
** words to ensure coherency. Since a bool may be
** smaller than a word, storing a bool may be implemented
** in a coherency-breaking manner.
** (Assuming that Words can be read and written in a
** coherent manner is sufficiently important in terms of
** simplifying the synchronization mechanisms, that
** we really need to do so -- or so says Tom, at least.
** I remain unconvinced. -Fergus.)
*/
typedef Word AtomicBool;
extern AtomicBool *procwaiting;
/*
** my_procnum is the number of the current process.
** my_procnum == 0 is the original parent process.
*/
extern int my_procnum;
extern pid_t my_procid;
/* do a context switch */
Declare_entry(do_runnext);
#define runnext() GOTO(ENTRY(do_runnext));
/*
** schedule(Context *cptr, Code *resume):
*/
#define schedule(cptr, resume) do { \
fatal_error("schedule not implemented"); \
} while(0)
/*
** fork_new_context(Code *child, Code *parent, int numslots):
** create a new context to execute the code at `child', and
** copy the topmost `numslots' from the current stackframe.
** The new context gets put on the runqueue, and the current
** context resumes at `parent'.
*/
#define fork_new_context(child, parent, numslots) do { \
Context *fork_new_context_context; \
int fork_new_context_i; \
fork_new_context_context = new_context(); \
for (fork_new_context_i = (numslots) ; \
fork_new_context_i > 0 ; \
fork_new_context_i--) { \
*(fork_new_context_context->context_sp) = \
detstackvar(fork_new_context_i); \
fork_new_context_context->context_sp++; \
} \
fork_new_context_context->resume = (child); \
schedule(fork_new_context_context, (parent)); \
} while (0)
#ifndef CONSERVATIVE_GC
/*
** To figure out the maximum amount of heap we can reclaim on backtracking,
** we compare hp with the context_hp.
**
** If context_hp == NULL then this is the first time this context has been
** scheduled, so the furthest back down the heap we can reclaim is to the
** current value of hp.
**
** If hp > context_hp, another context has allocated data on the heap since
** we were last scheduled, so the furthest back that we can reclaim is to
** the current value of hp, so we set MR_min_hp_rec and the
** field of the same name in our context structure.
**
** If hp < context_hp, then another context has truncated the heap on failure.
** For this to happen, it must be the case that last time we were scheduled,
** that other context was the last one to allocate data on the heap, and we
** did not allocate any heap during that period of execution. That being the
** case, the furthest back to which we can reset the heap is to the current
** value of hp. This is a conservative approximation - it is possible that
** the current value of hp is the same as some previous value that we held,
** and we are now contiguous with our older data, so this algorithm will lead
** to holes in the heap, though GC will reclaim these.
**
** If hp == context_hp then no other process has allocated any heap since we
** were last scheduled, so we can proceed as if we had not stopped, and the
** furthest back that we can backtrack is the same as it was last time we
** were executing.
*/
#define set_min_heap_reclamation_point(ctxt) do { \
if (hp != (ctxt)->context_hp \
|| (ctxt)->context_hp == NULL) \
{ \
MR_min_hp_rec = hp; \
(ctxt)->min_hp_rec = hp;\
} \
else \
{ \
MR_min_hp_rec = (ctxt)->min_hp_rec; \
} \
} while (0)
#define save_hp_in_context(ctxt) do { \
(ctxt)->context_hp = hp; \
(ctxt)->min_hp_rec = MR_min_hp_rec; \
} while (0)
#else
#define set_min_heap_reclamation_point(ctxt) do { } while (0)
#define save_hp_in_context(ctxt) do { } while (0)
#endif
#ifdef MR_USE_TRAIL
#define MR_IF_USE_TRAIL(x) x
#else
#define MR_IF_USE_TRAIL(x)
#endif
#define load_context(cptr) do { \
Context *load_context_c; \
load_context_c = (cptr); \
MR_succip = load_context_c->context_succip; \
detstack_zone = load_context_c->detstack_zone; \
MR_sp = load_context_c->context_sp; \
nondetstack_zone = load_context_c->nondetstack_zone; \
MR_maxfr = load_context_c->context_maxfr; \
MR_curfr = load_context_c->context_curfr; \
MR_IF_USE_TRAIL( \
MR_trail_zone = load_context_c->trail_zone; \
MR_trail_ptr = load_context_c->context_trail_ptr; \
MR_ticket_counter = \
load_context_c->context_ticket_counter; \
) \
set_min_heap_reclamation_point(load_context_c); \
} while (0)
#define save_context(cptr) do { \
Context *save_context_c; \
save_context_c = (cptr); \
save_context_c->context_succip = MR_succip; \
save_context_c->detstack_zone = detstack_zone; \
save_context_c->context_sp = MR_sp; \
save_context_c->nondetstack_zone = nondetstack_zone; \
save_context_c->context_maxfr = MR_maxfr; \
save_context_c->context_curfr = MR_curfr; \
MR_IF_USE_TRAIL( \
save_context_c->trail_zone = MR_trail_zone; \
save_context_c->context_trail_ptr = MR_trail_ptr; \
save_context_c->context_ticket_counter = \
MR_ticket_counter; \
) \
save_hp_in_context(save_context_c); \
} while (0)
/*
** The following two macros join_and_terminate and join_and_continue
** both take a `sync_term' which has the following structure:
** sync_term[SYNC_TERM_LOCK] is a SpinLock
** sync_term[SYNC_TERM_COUNTER] is a counter for the number of
** processes that need to synchronize before the
** parent can proceed.
** sync_term[SYNC_TERM_PARENT] is either NULL or a pointer to the
** context of the parent process. If it is non-null
** then the last process to arrive (the one that
** decrements sync_term[SYNC_TERM_COUNTER] to 0)
** must wake the parent.
** These terms are allocated and manipulated as normal Mercury terms by
** generated Mercury code.
*/
#define SYNC_TERM_LOCK 0
#define SYNC_TERM_COUNTER 1
#define SYNC_TERM_PARENT 2
#define join_and_terminate(sync_term) do { \
fatal_error("join_and_terminate not implemented"); \
} while (0)
#define join_and_continue(sync_term, where_to) do { \
fatal_error("join_and_continue not implemented"); \
} while (0)
#endif

137
runtime/mercury_debug.h Normal file
View File

@@ -0,0 +1,137 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* debug.h - definitions for debugging messages */
#ifndef DEBUG_H
#define DEBUG_H
#ifdef DEBUG_ON
#define DEBUG(X) X
#else
#define DEBUG(X)
#endif
#endif
#if defined(SPEED) && !defined(DEBUG_GOTOS)
#define debuggoto(label) ((void)0)
#define debugsreg() ((void)0)
#else
#define debuggoto(label) \
(MR_assert(label), \
IF (gotodebug, (save_transient_registers(), goto_msg(label))))
#define debugsreg() \
IF (sregdebug, (save_transient_registers(), reg_msg()))
#endif
#ifdef SPEED
#define dump_push_msg(msg) ((void)0)
#define dump_pop_msg() ((void)0)
#define debugcr1(val0, hp) ((void)0)
#define debugcr2(val0, val1, hp) ((void)0)
#define debugincrhp(val, hp) ((void)0)
#define debugincrsp(val, sp) ((void)0)
#define debugdecrsp(val, sp) ((void)0)
#define debugpush(val, sp) ((void)0)
#define debugpop(val, sp) ((void)0)
#define debugregs(msg) ((void)0)
#define debugframe(msg) ((void)0)
#define debugmkframe() ((void)0)
#define debugmodframe() ((void)0)
#define debugsucceed() ((void)0)
#define debugsucceeddiscard() ((void)0)
#define debugfail() ((void)0)
#define debugredo() ((void)0)
#define debugcall(proc, succ_cont) ((void)0)
#define debugtailcall(proc) ((void)0)
#define debugproceed() ((void)0)
#define debugmsg0(msg) ((void)0)
#define debugmsg1(msg, arg1) ((void)0)
#define debugmsg2(msg, arg1, arg2) ((void)0)
#define debugmsg3(msg, arg1, arg2, arg3) ((void)0)
#else
#define dump_push_msg(msg) \
(((const char **)dumpstack_zone->min)[dumpindex++] = msg)
#define dump_pop_msg() (--dumpindex)
#define debugcr1(val0, hp) \
IF (heapdebug, (save_transient_registers(), cr1_msg(val0, hp)))
#define debugcr2(val0, val1, hp) \
IF (heapdebug, (save_transient_registers(), cr2_msg(val0, val1, hp)))
#define debugincrhp(val, hp) \
IF (heapdebug, (save_transient_registers(), incr_hp_msg((val), (hp))))
#define debugincrsp(val, sp) \
IF (detstackdebug, (save_transient_registers(), incr_sp_msg((val), (sp))))
#define debugdecrsp(val, sp) \
IF (detstackdebug, (save_transient_registers(), decr_sp_msg((val), (sp))))
#define debugpush(val, sp) \
IF (detstackdebug, (save_transient_registers(), push_msg((val), (sp))))
#define debugpop(val, sp) \
IF (detstackdebug, (save_transient_registers(), pop_msg(val, sp)))
#define debugregs(msg) \
IF (progdebug, (save_transient_registers(), printregs(msg)))
#define debugmkframe() \
IF (nondstackdebug, (save_transient_registers(), mkframe_msg()))
#define debugframe(msg) \
IF (progdebug, (save_transient_registers(), printframe(msg)))
#define debugmodframe() \
IF (nondstackdebug, (save_transient_registers(), modframe_msg()))
#define debugsucceed() \
IF (nondstackdebug, (save_transient_registers(), succeed_msg()))
#define debugsucceeddiscard() \
IF (nondstackdebug, (save_transient_registers(), succeeddiscard_msg()))
#define debugfail() \
IF (nondstackdebug, (save_transient_registers(), fail_msg()))
#define debugredo() \
IF (nondstackdebug, (save_transient_registers(), redo_msg()))
#define debugcall(proc, succ_cont) \
IF (calldebug, (save_transient_registers(), call_msg(proc, succ_cont)))
#define debugtailcall(proc) \
IF (calldebug, (save_transient_registers(), tailcall_msg(proc)))
#define debugproceed() \
IF (calldebug, (save_transient_registers(), proceed_msg()))
#define debugmsg0(msg) \
IF (progdebug, (printf(msg)))
#define debugmsg1(msg, arg1) \
IF (progdebug, (printf(msg, arg1)))
#define debugmsg2(msg, arg1, arg2) \
IF (progdebug, (printf(msg, arg1, arg2)))
#define debugmsg3(msg, arg1, arg2, arg3) \
IF (progdebug, (printf(msg, arg1, arg2, arg3)))
#endif

View File

@@ -0,0 +1,65 @@
/*
** Copyright (C) 1997 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.
*/
/* deepcopy.h - declares the deep_copy() function. */
#ifndef DEEP_COPY_H
#define DEEP_COPY_H
#include "mercury_types.h" /* for `Word' */
/* Deep Copy:
**
** Copy a data item, completely.
**
** The copying is done depth first. Any part of the data
** structure that is outside the given upper and lower
** bounds not be copied, instead a reference to the
** original data will be used. For conservative gc grades,
** the entire data structure will be copied, as there is no
** heap.
**
** The caller must provide the type_info describing
** the type of this data structure. It must also
** provide the heap_limit - if no limit is desired,
** NULL or the bottom of the heap may be passed.
** deep_copy returns the address of the new, copied
** data structure.
**
** Deep copy returns the actual data that it copied,
** which may need to be stored on the heap, or put in
** a register or stack slot (depending on what you
** are using deep copy for). This may be a tagged pointer,
** or if the data is just a simple type like a constant
** or integer, it will be the constant or integer itself.
**
** Please note - deep_copy increments the heap pointer,
** however on some platforms (notably, SPARCs) the
** register-windows mean the transient Mercury registers
** may be lost. So before calling deep_copy, call
** save_transient_registers();
**
** deep_copy will use restore_transient_registers()
** to restore the registers and modify the heap pointer, and
** then call save_transient_registers() to save them again.
** (This behaviour may change in future - it may be more
** efficient to just change the saved register - so do not rely on
** it).
**
** After calling deep_copy, be sure to do a
** restore_transient_registers();
** so that the registers are restored.
**
** If writing a C function that calls deep_copy, make sure
** you document that around your function,
** save_transient_registers()/restore_transient_registers()
** need to be used.
*/
Word deep_copy(Word data, Word *type_info, Word *lower_limit,
Word *upper_limit);
#endif /* not DEEP_COPY_H */

71
runtime/mercury_dlist.h Normal file
View File

@@ -0,0 +1,71 @@
/*
** Copyright (C) 1995-1997 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.
*/
/*
** dlist.h - defines a doubly-linked list type.
*/
#ifndef DLIST_H
#define DLIST_H
/*
** The lists we use are doubly-linked.
** They each have a header node, and we store the length of the list
** in the header node.
*/
typedef struct s_list {
union {
void *l_data;
int l_length;
} l_union;
struct s_list *l_prev;
struct s_list *l_next;
} List;
#define next(ptr) (ptr)->l_next
#define prev(ptr) (ptr)->l_prev
#define ldata(ptr) (ptr)->l_union.l_data
#define llength(list) ((list)->l_union.l_length)
#define first_ptr(list) ((list)->l_next)
#define last_ptr(list) ((list)->l_prev)
#define first(list) ((list)->l_next->l_union.l_data)
#define last(list) ((list)->l_prev->l_union.l_data)
#define makelist(d) list_makelist(d)
#define addhead(l, d) list_addhead(l, d)
#define addtail(l, d) list_addtail(l, d)
#define insert_before(l, w, d) list_insert_before(l, w, d)
#define insert_after(l, w, d) list_insert_after(l, w, d)
#define for_list(p, l) \
for (p = (l? next(l): NULL); p != l && p != NULL; p = next(p))
#define for_2list(p1, p2, l1, l2) \
for ( \
p1 = (l1? next(l1): NULL), p2 = (l2? next(l2): NULL); \
p1 != l1 && p1 != NULL && p2 != l2 && p2 != NULL; \
p1 = next(p1), p2 = next(p2) \
)
#define for_unlist(p, np, l) \
for (p = (l? next(l): NULL), np = (p? next(p): NULL); \
p != l && p != NULL; \
p = np, np = (p? next(p): NULL))
#define end_list(p, l)\
(p == l || p == NULL)
extern List *makelist0(void);
extern List *list_makelist(void *);
extern List *list_addhead(List *, void *);
extern List *list_addtail(List *, void *);
extern List *addlist(List *, List *);
extern List *addndlist(List *, List *);
extern void list_insert_before(List *, List *, void *);
extern void list_insert_after(List *, List *, void *);
extern int length(const List *);
extern void dlist_delete(List *, List *, void (*)(void *));
extern void oldlist(List *, void (*)(void *));
#endif /* not DLIST_H */

22
runtime/mercury_dummy.h Normal file
View File

@@ -0,0 +1,22 @@
/*
** Copyright (C) 1993-1995 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.
*/
/*
** File: dummy.h
** Author: fjh
**
** Global variables and functions used purely for the purpose
** of suppressing over-zealous compiler optimizations.
*/
#ifndef DUMMY_H
#define DUMMY_H
extern void dummy_function_call(void);
extern void *global_pointer;
extern void *global_pointer_2;
#endif

View File

@@ -1,4 +1,8 @@
/*
INIT mercury_sys_init_engine
ENDINIT
*/
/*
** Copyright (C) 1993-1997 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.
@@ -386,29 +390,42 @@ terminate_engine(void)
/*---------------------------------------------------------------------------*/
BEGIN_MODULE(special_labels_module)
Define_extern_entry(do_redo);
Define_extern_entry(do_fail);
Define_extern_entry(do_succeed);
Define_extern_entry(do_last_succeed);
Define_extern_entry(do_not_reached);
BEGIN_MODULE(special_labels_module)
init_entry(do_redo);
init_entry(do_fail);
init_entry(do_succeed);
init_entry(do_last_succeed);
init_entry(do_not_reached);
BEGIN_CODE
do_redo:
Define_entry(do_redo);
redo();
do_fail:
Define_entry(do_fail);
fail();
do_succeed:
Define_entry(do_succeed);
succeed();
do_last_succeed:
Define_entry(do_last_succeed);
succeed_discard();
do_not_reached:
Define_entry(do_not_reached);
printf("reached not_reached\n");
exit(1);
#ifndef USE_GCC_NONLOCAL_GOTOS
return 0;
#endif
END_MODULE
/*---------------------------------------------------------------------------*/
void mercury_sys_init_engine(void); /* suppress gcc warning */
void mercury_sys_init_engine(void) {
special_labels_module();
}

149
runtime/mercury_engine.h Normal file
View File

@@ -0,0 +1,149 @@
/*
** Copyright (C) 1994-1997 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.
*/
/*
** engine.h - definitions for the Mercury runtime engine.
**
** For documentation, see the comments in engine.mod.
*/
#ifndef ENGINE_H
#define ENGINE_H
#include <setjmp.h>
#include "std.h" /* for `bool' */
#include "mercury_types.h" /* for `Code *' */
#include "goto.h" /* for `Define_entry()' */
#include "regs.h" /* for NUM_REAL_REGS */
#define PROGFLAG 0
#define GOTOFLAG 1
#define CALLFLAG 2
#define HEAPFLAG 3
#define DETSTACKFLAG 4
#define NONDSTACKFLAG 5
#define FINALFLAG 6
#define MEMFLAG 7
#define SREGFLAG 8
#define TRACEFLAG 9
#define DETAILFLAG 10
#define MAXFLAG 11
/* DETAILFLAG should be the last real flag */
#define progdebug debugflag[PROGFLAG]
#define gotodebug debugflag[GOTOFLAG]
#define calldebug debugflag[CALLFLAG]
#define heapdebug debugflag[HEAPFLAG]
#define detstackdebug debugflag[DETSTACKFLAG]
#define nondstackdebug debugflag[NONDSTACKFLAG]
#define finaldebug debugflag[FINALFLAG]
#define memdebug debugflag[MEMFLAG]
#define sregdebug debugflag[SREGFLAG]
#define tracedebug debugflag[TRACEFLAG]
#define detaildebug debugflag[DETAILFLAG]
/*
** 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_jmp_buf
*/
jmp_buf env; /*
** used by calls to setjmp and longjmp
*/
Word *saved_succip;
Word *saved_sp;
Word *saved_curfr;
Word *saved_maxfr;
MR_IF_USE_TRAIL(Word *saved_trail_ptr;)
MR_IF_USE_TRAIL(Word *saved_ticket_counter;)
#if NUM_REAL_REGS > 0
Word regs[NUM_REAL_REGS];
#endif /* NUM_REAL_REGS > 0 */
} MR_jmp_buf;
/*
** MR_setjmp(MR_jmp_buf *env, longjmp_label)
**
** Save MR_engine_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 r1, 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_jmp_buf; \
save_regs_to_mem((setjmp_env)->regs); \
(setjmp_env)->saved_succip = succip; \
(setjmp_env)->saved_sp = sp; \
(setjmp_env)->saved_curfr = curfr; \
(setjmp_env)->saved_maxfr = 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); \
if (setjmp((setjmp_env)->env)) { \
MR_engine_jmp_buf = (setjmp_env)->mercury_env; \
restore_regs_from_mem((setjmp_env)->regs); \
succip = (setjmp_env)->saved_succip; \
sp = (setjmp_env)->saved_sp; \
curfr = (setjmp_env)->saved_curfr; \
maxfr = (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); \
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)
/*
** engine_jmp_buf should only be referred to in engine.c
** and the MR_setjmp and MR_longjmp macros defined above.
*/
extern jmp_buf *MR_engine_jmp_buf;
extern bool debugflag[];
extern void init_engine(void);
extern void call_engine(Code *entry_point);
extern void terminate_engine(void);
extern void dump_prev_locations(void);
Declare_entry(do_redo);
Declare_entry(do_fail);
Declare_entry(do_reset_hp_fail);
Declare_entry(do_reset_framevar0_fail);
Declare_entry(do_succeed);
Declare_entry(do_not_reached);
#endif /* not ENGINE_H */

View File

@@ -9,7 +9,7 @@
#ifndef MERCURY_FLOAT_H
#define MERCURY_FLOAT_H
#include "conf.h" /* for BOXED_FLOAT */
#include "mercury_conf.h" /* for BOXED_FLOAT */
#include "mercury_types.h" /* for `Word' */
#ifdef USE_SINGLE_PREC_FLOAT

29
runtime/mercury_getopt.h Normal file
View File

@@ -0,0 +1,29 @@
/*
** Copyright (C) 1993-1997 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.
*/
/*
** getopt.h - declares the interface to the system function getopt()
**
** We use this file rather than the system's <getopt.h>
** because different systems have different ideas about
** where the `const's should go on the declaration of getopt().
** Also, some systems might have getopt() but not <getopt.h>.
*/
#ifndef GETOPT_H
#define GETOPT_H
#define GETOPTHUH '?'
#define GETOPTDONE (-1)
extern int getopt(int, char *const*, const char *);
extern char *optarg;
extern int opterr;
extern int optind;
extern int optopt;
#endif /* not GETOPT_H */

585
runtime/mercury_goto.h Normal file
View File

@@ -0,0 +1,585 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* goto.h - definitions for the "portable assembler" non-local gotos */
#ifndef GOTO_H
#define GOTO_H
#include "mercury_types.h" /* for `Code *' */
#include "debug.h" /* for debuggoto() */
/*
** Taking the address of a label can inhibit gcc's optimization,
** because it assumes that anything can jump there.
** Therefore we want to do it only if we're debugging,
** or if we need the label address for profiling.
*/
#if defined(SPEED) && !defined(DEBUG_GOTOS)
#define make_label(n, a) /* nothing */
#else
#define make_label(n, a) make_entry(n, a)
#endif
#if defined(SPEED) && !defined(DEBUG_GOTOS) && !defined(PROFILE_CALLS)
#define make_local(n, a) /* nothing */
#else
#define make_local(n, a) make_entry(n, a)
#endif
#if defined(SPEED) && !defined(DEBUG_LABELS) && !defined(DEBUG_GOTOS) \
&& !defined(PROFILE_CALLS)
#define make_entry(n, a) /* nothing */
#else
#define make_entry(n, a) insert_entry(n, a)
#endif
#define paste(a,b) a##b
#define stringify(string) #string
#define entry(label) paste(_entry_,label)
#define skip(label) paste(skip_,label)
#ifdef SPLIT_C_FILES
#define MODULE_STATIC_OR_EXTERN extern
#else
#define MODULE_STATIC_OR_EXTERN static
#endif
/*---------------------------------------------------------------------------*/
/* MACHINE SPECIFIC STUFF REQUIRED FOR NON-LOCAL GOTOS */
#if defined(__alpha__)
/* We need special handling for the "global pointer" (gp) register. */
/*
** When doing a jump, we need to set $27, the "procedure value" register,
** to the address we are jumping to, so that we can use an `ldgp'
** instruction on entry to the procedure to set up the right gp value.
*/
#define ASM_JUMP(address) \
__asm__("bis %0, %0, $27\n\t" \
: : "r"(address) : "$27"); \
goto *(address)
/*
** Explanation:
** Move `address' to register $27,
** jump to `address'.
*/
/*
** on entry to a procedure, we need to load the $gp register
** with the correct value relative to the current address in $27
*/
#define INLINE_ASM_FIXUP_REGS \
" ldgp $gp, 0($27)\n" : : : "memory"
/*
** on fall-thru, we need to skip the ldgp instruction
*/
#define ASM_FALLTHROUGH(label) \
goto skip(label);
#elif defined(__i386__)
/*
** The following hack works around a stack leak on the i386.
** The problem is that gcc pushes function parameters onto
** the stack when calling C functions such as GC_malloc(),
** and only restores the stack pointer in the epilogue.
** With non-local gotos, we jump out of the function without
** executing its epilogue, so the stack pointer never gets
** restored. The result is a memory leak; for example,
** `mc --generate-dependencies mercury_compile' exceeds the
** Slackware Linux default stack space limit of 8M.
**
** GNU C has an option `-fno-defer-pop' which is supposed to
** avoid this sort of thing, but it doesn't work for our
** code using non-local gotos.
**
** We work around this using the dummy assembler code below, which
** pretends to use the stack pointer, forcing gcc to flush any updates
** of the stack pointer immediately, rather than deferring them until
** the function epilogue.
**
** I know this is awful. It wasn't _my_ idea to use non-local gotos ;-)
*/
#define ASM_JUMP(label) \
{ register int stack_pointer __asm__("esp"); \
__asm__("" : : "g"(stack_pointer)); } \
goto *(label)
/*
** That hack above needs to be done for all non-local jumps,
** even if we're not using assembler labels.
*/
#define JUMP(label) ASM_JUMP(label)
/*
** If we're using position-independent code on i386, then we need to
** set up the correct value of the GOT register (ebx).
*/
#if (defined(__pic__) || defined(__PIC__)) && !defined(PIC)
#define PIC 1
#endif
#if PIC
/*
** At each entry point, where we may have been jump to from
** code in a difference C file, we need to set up `ebx'.
** We do this by pushing the IP register using a `call'
** instruction whose target is the very next label.
** We then pop this off the stack into `ebx', and
** then use the value obtained to compute the correct
** value of `ebx' by doing something with _GLOBAL_OFFSET_TABLE_
** (I don't understand the details exactly, this code is
** basically copied from the output of `gcc -fpic -S'.)
** Note that `0f' means the label `0:' following the current
** instruction, and `0b' means the label `0:' before the current
** instruction.
**
** Note: this code clobbers `ebx', which is a callee-save
** register. That means that it is essential that call_engine()
** save `ebx' before entering Mercury code, and restore it
** before returning to C code. However, gcc and/or
** setjmp()/longjmp() will do that for us automatically,
** precisely because it is a callee-save register.
*/
#define INLINE_ASM_FIXUP_REGS \
" call 0f\n" \
"0:\n" \
" popl %%ebx\n" \
" addl $_GLOBAL_OFFSET_TABLE_+[.-0b],%%ebx\n\t" \
: :
#if 0
/*
** The following doesn't seem to be necessary, and
** leaving it out might make gcc generate slightly better code.
*/
/* tell gcc we clobber ebx and memory */ \
: : : "%ebx", "memory"
#endif
/*
** It is safe to fall through into INLINE_ASM_FIXUP_REGS,
** but it might be more efficient to branch past it.
** We should really measure both ways and find out which is
** better... for the moment, we just fall through, since
** that keeps the code smaller.
*/
#if 0
#define ASM_FALLTHROUGH(label) \
goto skip(label);
#endif
#endif /* PIC */
/* For Linux-ELF shared libraries, we need to declare that the type of labels
** is @function (i.e. code, not data), otherwise the dynamic linker seems
** to get confused, and we end up jumping into the data section.
** Hence the `.type' directive below.
*/
#ifdef __ELF__
#define INLINE_ASM_ENTRY_LABEL_TYPE(label) \
" .type _entry_" stringify(label) ",@function\n"
#endif
#elif defined (__sparc)
/*
** If we're using position-independent code on the SPARC, then we need to
** set up the correct value of the GOT register (l7).
*/
#if (defined(__pic__) || defined(__PIC__)) && !defined(PIC)
#define PIC 1
#endif
#if PIC
/*
** At each entry point, where we may have been jump to from
** code in a difference C file, we need to set up `l7'.
** We do this by getting the value the of the IP register using a `call'
** instruction whose target is the very next label; this will
** put the address of the call instruction in register `o7'.
** We then use the value obtained in register `o7' to compute the correct
** value of register `l7' by doing something with _GLOBAL_OFFSET_TABLE_
** (I don't understand the details exactly, this code is
** basically copied from the output of `gcc -fpic -S'.)
** Note that `1f' means the label `1:' following the current
** instruction, and `0b' means the label `0:' before the current
** instruction.
*/
#define INLINE_ASM_FIXUP_REGS \
"0:\n" \
" call 1f\n" \
" nop\n" \
"1:\n" \
" sethi %%hi(_GLOBAL_OFFSET_TABLE_-(0b-.)),%%l7\n" \
" or %%l7,%%lo(_GLOBAL_OFFSET_TABLE_-(0b-.)),%%l7\n" \
" add %%l7,%%o7,%%l7\n" \
/* tell gcc we clobber l7, o7, and memory */ \
: : : "%l7", "%o7", "memory"
/*
** It is safe to fall through into INLINE_ASM_FIXUP_REGS,
** but it might be more efficient to branch past it.
** We should really measure both ways and find out which is
** better... for the moment, we just fall through, since
** that keeps the code smaller.
*/
#if 0
#define ASM_FALLTHROUGH(label) \
goto skip(label);
#endif
#endif /* PIC */
/*
** For Solaris 5.5.1, we need to declare that the type of labels is
** #function (i.e. code, not data), otherwise the dynamic linker seems
** to get confused, and we end up jumping into the data section.
** Hence the `.type' directive below.
*/
#ifndef MR_CANNOT_GROK_ASM_TYPE_DIRECTIVE
#define INLINE_ASM_ENTRY_LABEL_TYPE(label) \
" .type _entry_" stringify(label) ",#function\n"
#endif
#endif
/* for other architectures, these macros have default definitions */
/*
** INLINE_ASM_FIXUP_REGS is used to fix up the value of
** any registers after an ASM_JUMP to an entry point, if necessary.
** It is an assembler string, possibly followed by `: : : <clobbers>'
** where <clobbers> is an indication to gcc of what gets clobbered.
*/
#ifdef INLINE_ASM_FIXUP_REGS
#define ASM_FIXUP_REGS \
__asm__ __volatile__( \
INLINE_ASM_FIXUP_REGS \
);
#define NEED_ASM_FIXUP_REGS
#else
#define ASM_FIXUP_REGS
#define INLINE_ASM_FIXUP_REGS
#undef NEED_ASM_FIXUP_REGS
#endif
/*
** ASM_FALLTHROUGH is executed when falling through into an entry point.
** It may call `goto skip(label)' if it wishes to skip past the
** label and the INLINE_ASM_FIXUP_REGS code.
*/
#ifndef ASM_FALLTHROUGH
#define ASM_FALLTHROUGH(label)
#endif
/*
** INLINE_ASM_GLOBALIZE_LABEL is an assembler string to
** declare an entry label as global. The following definition
** using `.globl' should work with the GNU assembler and
** with most Unix assemblers.
*/
#ifndef INLINE_ASM_GLOBALIZE_LABEL
#define INLINE_ASM_GLOBALIZE_LABEL(label) \
" .globl _entry_" stringify(label) "\n"
#endif
/*
** INLINE_ASM_ENTRY_LABEL_TYPE is an assembler string to
** declare the "type" of a label as function (i.e. code), not data,
** if this is needed.
*/
#ifndef INLINE_ASM_ENTRY_LABEL_TYPE
#define INLINE_ASM_ENTRY_LABEL_TYPE(label)
#endif
/*
** INLINE_ASM_ENTRY_LABEL is an assembler string to
** define an assembler entry label.
*/
#ifndef INLINE_ASM_ENTRY_LABEL
#define INLINE_ASM_ENTRY_LABEL(label) \
"_entry_" stringify(label) ":\n"
#endif
/*
** ASM_JUMP is used to jump to an entry point defined with
** ASM_ENTRY, ASM_STATIC_ENTRY, or ASM_LOCAL_ENTRY.
*/
#ifndef ASM_JUMP
#define ASM_JUMP(address) goto *(address)
#endif
/*---------------------------------------------------------------------------*/
/* The code from here on should be architecture-independent. */
/*---------------------------------------------------------------------------*/
/*
** ASM_ENTRY is used to declare an external entry point
** using a (global) assembler label.
*/
#define ASM_ENTRY(label) \
ASM_FALLTHROUGH(label) \
entry(label): \
__asm__ __volatile__( \
INLINE_ASM_GLOBALIZE_LABEL(label) \
INLINE_ASM_ENTRY_LABEL_TYPE(label) \
INLINE_ASM_ENTRY_LABEL(label) \
INLINE_ASM_FIXUP_REGS \
); \
skip(label): ;
/*
** ASM_STATIC_ENTRY is the same as ASM_ENTRY,
** except that its scope is local to a C file, rather than global.
** Note that even static entry points must do INLINE_ASM_FIXUP_REGS,
** since although there won't be any direct calls to them from another
** C file, their address may be taken and so there may be indirect
** calls.
*/
#define ASM_STATIC_ENTRY(label) \
ASM_FALLTHROUGH(label) \
entry(label): \
__asm__ __volatile__( \
INLINE_ASM_ENTRY_LABEL_TYPE(label) \
INLINE_ASM_ENTRY_LABEL(label) \
INLINE_ASM_FIXUP_REGS \
); \
skip(label): ;
/*
** ASM_LOCAL_ENTRY is the same as ASM_ENTRY,
** except that its scope is local to a BEGIN_MODULE...END_MODULE
** block, rather than being global.
** Note that even local entry points must do INLINE_ASM_FIXUP_REGS, since
** although there won't be any direct calls to them from another
** C file, their address may be taken and so there may be indirect
** calls.
*/
#define ASM_LOCAL_ENTRY(label) \
ASM_FALLTHROUGH(label) \
entry(label): \
ASM_FIXUP_REGS \
skip(label): ;
/*---------------------------------------------------------------------------*/
#if defined(USE_GCC_NONLOCAL_GOTOS)
#ifndef __GNUC__
#error "You must use gcc if you define USE_GCC_NONLOCAL_GOTOS"
#endif
/* Define the type of a module initialization function */
typedef void ModuleFunc(void);
/* The following macro expands to a dummy assembler statement which
** contains no code, but which tells gcc that it uses the specified
** address as an input value. This is used to trick gcc into
** thinking that the address is used, in order to suppress unwanted
** optimizations. (We used to use `volatile_global_pointer =
** address' to suppress optimization, but this way is better because
** it doesn't generate any code.)
*/
#define PRETEND_ADDRESS_IS_USED(address) \
__asm__ __volatile__("" : : "g"(address))
/*
Explanation:
__asm__
__volatile__ don't optimize this asm away
(
"" empty assembler code
: no outputs
: "g" (address) one input value, `address';
"g" means that it can go in any
general-purpose register
)
*/
/* Since we're jumping into and out of the middle of functions,
** we need to make sure that gcc thinks that (1) the function's address
** is used (otherwise it may optimize the whole function away) and
** (2) the `return' statement is reachable (otherwise its dataflow
** analysis for delay slot scheduling may think that global
** register variables which are only assigned to in the function
** cannot be live, when in fact they really are).
** That is what the two occurrences of the PRETEND_ADDRESS_IS_USED
** macro are for.
*/
#define BEGIN_MODULE(module_name) \
MODULE_STATIC_OR_EXTERN void module_name(void); \
MODULE_STATIC_OR_EXTERN void module_name(void) { \
PRETEND_ADDRESS_IS_USED(module_name); \
PRETEND_ADDRESS_IS_USED(&& paste(module_name, _dummy_label)); \
paste(module_name,_dummy_label): \
{
/* initialization code for module goes here */
#define BEGIN_CODE } return; {
/* body of module goes here */
#define END_MODULE } }
#if defined(USE_ASM_LABELS)
#define Declare_entry(label) \
extern void label(void) __asm__("_entry_" stringify(label))
#define Declare_static(label) \
static void label(void) __asm__("_entry_" stringify(label))
#define Define_extern_entry(label) Declare_entry(label)
#define Define_entry(label) \
ASM_ENTRY(label) \
} \
label: \
PRETEND_ADDRESS_IS_USED(&&entry(label)); \
{
#define Define_static(label) \
ASM_STATIC_ENTRY(label) \
} \
label: \
PRETEND_ADDRESS_IS_USED(&&entry(label)); \
{
/*
** The PRETEND_ADDRESS_IS_USED macro is necessary to
** prevent an over-zealous gcc from optimizing away `label'
** and the code that followed.
*/
#define init_entry(label) \
PRETEND_ADDRESS_IS_USED(&&label); \
make_entry(stringify(label), label)
#define ENTRY(label) (&label)
#define STATIC(label) (&label)
#ifndef JUMP
#define JUMP(label) ASM_JUMP(label)
#endif
#else
/* !defined(USE_ASM_LABELS) */
#define Declare_entry(label) extern Code * entry(label)
#define Declare_static(label) static Code * entry(label)
#define Define_extern_entry(label) Code * entry(label)
#define Define_entry(label) \
} \
entry(label): \
label: \
{
#define Define_static(label) \
} \
entry(label): \
label: \
{
#define init_entry(label) \
make_entry(stringify(label), &&label); \
entry(label) = &&label
#define ENTRY(label) (entry(label))
#define STATIC(label) (entry(label))
#ifndef JUMP
#define JUMP(label) goto *(label)
#endif
#endif /* !defined(USE_ASM_LABELS) */
#define Declare_local(label) /* no declaration required */
#define Define_local(label) \
ASM_LOCAL_ENTRY(label) \
} \
label: \
{
#define init_local(label) make_local(stringify(label), &&label)
#define Declare_label(label) /* no declaration required */
#define Define_label(label) Define_local(label)
#define init_label(label) make_label(stringify(label), &&label)
#define LOCAL(label) (&&entry(label))
#define LABEL(label) (&&entry(label))
#define GOTO(label) do { debuggoto(label); JUMP(label); } while(0)
#define GOTO_ENTRY(label) GOTO(ENTRY(label))
#define GOTO_STATIC(label) GOTO(STATIC(label))
#define GOTO_LOCAL(label) GOTO_LABEL(label)
#define GOTO_LABEL(label) do { debuggoto(&&label); goto label; } while(0)
/*
** GOTO_LABEL(label) is the same as GOTO(LABEL(label)) except
** that it may allow gcc to generate slightly better code
*/
#else
/* !defined(USE_GCC_NONLOCAL_GOTOS) */
/* Define the type of a module initialization function */
typedef Code * ModuleFunc(void);
#define BEGIN_MODULE(module_name) \
MODULE_STATIC_OR_EXTERN Code* module_name(void); \
MODULE_STATIC_OR_EXTERN Code* module_name(void) {
#define BEGIN_CODE return 0;
#define END_MODULE }
#define Declare_entry(label) extern void *label(void)
#define Declare_static(label) static void *label(void)
#define Define_extern_entry(label) void *label(void)
#define Define_entry(label) \
GOTO(label); \
} \
Code* label(void) {
#define Define_static(label) \
GOTO(label); \
} \
static Code* label(void) {
#define init_entry(label) make_entry(stringify(label), label)
#define Declare_local(label) static Code *label(void)
#define Define_local(label) \
GOTO(label); \
} \
static Code* label(void) {
#define init_local(label) make_local(stringify(label), label)
#define Declare_label(label) static Code *label(void)
#define Define_label(label) \
GOTO(label); \
} \
static Code* label(void) {
#define init_label(label) make_label(stringify(label), label)
#define ENTRY(label) (label)
#define STATIC(label) (label)
#define LOCAL(label) (label)
#define LABEL(label) (label)
#define GOTO(label) return (label)
/* the call to debuggoto() is in engine.mod */
#define GOTO_ENTRY(label) GOTO(ENTRY(label))
#define GOTO_STATIC(label) GOTO(STATIC(label))
#define GOTO_LOCAL(label) GOTO(LOCAL(label))
#define GOTO_LABEL(label) GOTO(LABEL(label))
#endif /* !defined(USE_GCC_NONLOCAL_GOTOS) */
/* definitions for computed gotos */
#define COMPUTED_GOTO(val, labels) \
{ static Code *jump_table[] = { \
labels \
}; \
GOTO(jump_table[val]); \
}
#define AND , /* used to separate the labels */
#endif /* not GOTO_H */

192
runtime/mercury_heap.h Normal file
View File

@@ -0,0 +1,192 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* heap.h - definitions for manipulating the Mercury heap */
#ifndef HEAP_H
#define HEAP_H
#include "mercury_types.h" /* for `Word' */
#include "context.h" /* for min_heap_reclamation_point() */
#ifdef CONSERVATIVE_GC
#include "gc.h"
#define tag_incr_hp_n(dest,tag,count) \
((dest) = (Word)mkword((tag), (Word)GC_MALLOC((count) * sizeof(Word))))
#define tag_incr_hp_atomic(dest,tag,count) \
((dest) = (Word)mkword((tag), \
(Word)GC_MALLOC_ATOMIC((count) * sizeof(Word))))
#ifdef INLINE_ALLOC
/*
** The following stuff uses the macros in the `gc_inl.h' header file in the
** Boehm garbage collector. They improve performance a little for
** highly allocation-intensive programs (e.g. the `nrev' benchmark).
** You'll probably need to fool around with the `-I' options to get this
** to work. Also, you must make sure that you compile with the same
** setting for -DSILENT that the boehm_gc directory was compiled with.
**
** We only want to inline allocations if the allocation size is a compile-time
** constant. This should be true for almost all the code that we generate,
** but with GCC we can use the `__builtin_constant_p()' extension to find out.
**
** The inline allocation macros are used only for allocating amounts
** of less than 16 words, to avoid fragmenting memory by creating too
** many distinct free lists. The garbage collector also requires that
** if we're allocating more than one word, we round up to an even number
** of words.
*/
#ifndef __GNUC__
/*
** Without the gcc extensions __builtin_constant_p() and ({...}),
** INLINE_ALLOC would probably be a performance _loss_.
*/
#error "INLINE_ALLOC requires the use of GCC"
#endif
#include "gc_inl.h"
#define tag_incr_hp(dest,tag,count) \
( __builtin_constant_p(count) && (count) < 16 \
? ({ void * temp; \
/* if size > 1, round up to an even number of words */ \
Word num_words = ((count) == 1 ? 1 : 2 * (((count) + 1) / 2)); \
GC_MALLOC_WORDS(temp, num_words); \
(dest) = (Word)mkword((tag), temp); \
}) \
: tag_incr_hp_n((dest),(tag),(count)) \
)
#else /* not INLINE_ALLOC */
#define tag_incr_hp(dest,tag,count) \
tag_incr_hp_n((dest),(tag),(count))
#endif /* not INLINE_ALLOC */
#define mark_hp(dest) ((void)0)
#define restore_hp(src) ((void)0)
/* we use `hp' as a convenient temporary here */
#define hp_alloc(count) (incr_hp(MR_hp,(count)), MR_hp += (count), (void)0)
#define hp_alloc_atomic(count) \
(incr_hp_atomic(MR_hp,(count)), MR_hp += (count), (void)0)
#else /* not CONSERVATIVE_GC */
#define tag_incr_hp(dest,tag,count) ( \
(dest) = (Word)mkword(tag, (Word)MR_hp), \
debugincrhp(count, MR_hp), \
MR_hp += (count), \
heap_overflow_check(), \
(void)0 \
)
#define tag_incr_hp_atomic(dest,tag,count) tag_incr_hp((dest),(tag),(count))
#define mark_hp(dest) ( \
(dest) = (Word)MR_hp, \
(void)0 \
)
/*
** When restoring hp, we must make sure that we don't truncate the heap
** further than it is safe to. We can only truncate it as far as
** min_heap_reclamation_point. See the comments in context.h next to
** the set_min_heap_reclamation_point() macro.
*/
#define restore_hp(src) ( \
LVALUE_CAST(Word,MR_hp) = \
( (Word) MR_min_hp_rec < (src) ? \
(src) : (Word) MR_min_hp_rec ), \
(void)0 \
)
#define hp_alloc(count) incr_hp(hp,count)
#define hp_alloc_atomic(count) incr_hp_atomic(count)
#endif /* not CONSERVATIVE_GC */
#define incr_hp(dest,count) tag_incr_hp((dest),mktag(0),(count))
#define incr_hp_atomic(dest,count) \
tag_incr_hp_atomic((dest),mktag(0),(count))
/*
** Note that gcc optimizes `hp += 2; return hp - 2;'
** to `tmp = hp; hp += 2; return tmp;', so we don't need to use
** gcc's expression statements here
*/
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create1(w1) ( \
hp_alloc(1), \
MR_hp[-1] = (Word) (w1), \
debugcr1(MR_hp[-1], MR_hp), \
/* return */ (Word) (MR_hp - 1) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create2(w1, w2) ( \
hp_alloc(2), \
MR_hp[-2] = (Word) (w1), \
MR_hp[-1] = (Word) (w2), \
debugcr2(MR_hp[-2], MR_hp[-1], MR_hp), \
/* return */ (Word) (MR_hp - 2) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create3(w1, w2, w3) ( \
hp_alloc(3), \
MR_hp[-3] = (Word) (w1), \
MR_hp[-2] = (Word) (w2), \
MR_hp[-1] = (Word) (w3), \
/* return */ (Word) (MR_hp - 3) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create2_bf(w1) ( \
MR_hp = MR_hp + 2, \
MR_hp[-2] = (Word) (w1), \
heap_overflow_check(), \
/* return */ (Word) (MR_hp - 2) \
)
/* used only by the hand-written example programs */
/* not by the automatically generated code */
#define create2_fb(w2) ( \
MR_hp = MR_hp + 2, \
MR_hp[-1] = (Word) (w2), \
heap_overflow_check(), \
/* return */ (Word) (MR_hp - 2) \
)
/*
** Indended for use in handwritten C code where the Mercury registers
** may have been clobbered due to C function calls (eg, on the SPARC due
** to sliding register windows).
** Remember to save_transient_registers() before calls to such code, and
** restore_transient_registers() after.
*/
#define incr_saved_hp(A,B) do { \
restore_transient_registers(); \
incr_hp((A), (B)); \
save_transient_registers(); \
} while (0)
#define incr_saved_hp_atomic(A,B) do { \
restore_transient_registers(); \
incr_hp_atomic((A), (B)); \
save_transient_registers(); \
} while (0)
#endif /* not HEAP_H */

View File

@@ -1,4 +1,8 @@
/*
INIT mercury_sys_init_call
ENDINIT
*/
/*
** Copyright (C) 1995-1997 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.
@@ -26,11 +30,39 @@
#include "imp.h"
BEGIN_MODULE(call_module)
Define_extern_entry(do_call_det_closure);
Declare_label(det_closure_return);
Define_extern_entry(do_call_semidet_closure);
Declare_label(semidet_closure_return);
Define_extern_entry(do_call_nondet_closure);
Declare_label(nondet_closure_return);
Define_extern_entry(mercury__unify_2_0);
Define_extern_entry(mercury__index_2_0);
Declare_label(mercury__index_2_0_i1);
Define_extern_entry(mercury__compare_3_0);
Define_extern_entry(mercury__compare_3_1);
Define_extern_entry(mercury__compare_3_2);
Define_extern_entry(mercury__compare_3_3);
Declare_label(mercury__compare_3_0_i1);
BEGIN_MODULE(call_module)
init_entry(do_call_det_closure);
init_label(det_closure_return);
init_entry(do_call_semidet_closure);
init_label(semidet_closure_return);
init_entry(do_call_nondet_closure);
init_label(nondet_closure_return);
init_entry(mercury__unify_2_0);
init_entry(mercury__index_2_0);
init_label(mercury__index_2_0_i1);
init_entry(mercury__compare_3_0);
init_entry(mercury__compare_3_1);
init_entry(mercury__compare_3_2);
init_entry(mercury__compare_3_3);
init_label(mercury__compare_3_0_i1);
BEGIN_CODE
do_call_det_closure:
Define_entry(do_call_det_closure);
{
Word closure;
int i, num_in_args, num_extra_args;
@@ -64,7 +96,7 @@ do_call_det_closure:
call((Code *) field(0, closure, 1), LABEL(det_closure_return),
LABEL(do_call_det_closure));
}
det_closure_return:
Define_label(det_closure_return);
{
int i, num_in_args, num_out_args;
@@ -86,7 +118,7 @@ det_closure_return:
proceed();
}
do_call_semidet_closure:
Define_entry(do_call_semidet_closure);
{
Word closure;
int i, num_in_args, num_extra_args;
@@ -136,7 +168,7 @@ do_call_semidet_closure:
call((Code *) field(0, closure, 1), LABEL(semidet_closure_return),
LABEL(do_call_semidet_closure));
}
semidet_closure_return:
Define_label(semidet_closure_return);
{
int i, num_in_args, num_out_args;
@@ -158,7 +190,7 @@ semidet_closure_return:
proceed();
}
do_call_nondet_closure:
Define_entry(do_call_nondet_closure);
{
Word closure;
int i, num_in_args, num_extra_args;
@@ -193,7 +225,7 @@ do_call_nondet_closure:
call((Code *) field(0, closure, 1), LABEL(nondet_closure_return),
LABEL(do_call_nondet_closure));
}
nondet_closure_return:
Define_label(nondet_closure_return);
{
int i, num_in_args, num_out_args;
@@ -231,7 +263,7 @@ nondet_closure_return:
** start either in r1 or r2 depending on the argument passing convention.
*/
mercury__unify_2_0:
Define_entry(mercury__unify_2_0);
{
Code *unify_pred; /* address of the unify pred for this type */
int type_arity; /* number of type_info args */
@@ -292,7 +324,7 @@ mercury__unify_2_0:
** routine a tail call, and we do so. With the simple convention, we can't.
*/
mercury__index_2_0:
Define_entry(mercury__index_2_0);
{
Code *index_pred; /* address of the index pred for this type */
int type_arity; /* number of type_info args */
@@ -339,7 +371,7 @@ mercury__index_2_0:
** Since mod2c declares this label, we must define it,
** even though it is not needed with COMPACT_ARGS.
*/
mercury__index_2_0_i1:
Define_label(mercury__index_2_0_i1);
{
#ifdef COMPACT_ARGS
fatal_error("mercury__index_2_0_i1 reached in COMPACT_ARGS mode");
@@ -379,25 +411,25 @@ mercury__index_2_0_i1:
** routine a tail call, and we do so. With the simple convention, we can't.
*/
mercury__compare_3_0:
Define_entry(mercury__compare_3_0);
#ifdef PROFILE_CALLS
{
tailcall(ENTRY(mercury__compare_3_3), LABEL(mercury__compare_3_0));
}
#endif
mercury__compare_3_1:
Define_entry(mercury__compare_3_1);
#ifdef PROFILE_CALLS
{
tailcall(ENTRY(mercury__compare_3_3), LABEL(mercury__compare_3_1));
}
#endif
mercury__compare_3_2:
Define_entry(mercury__compare_3_2);
#ifdef PROFILE_CALLS
{
tailcall(ENTRY(mercury__compare_3_3), LABEL(mercury__compare_3_2));
}
#endif
mercury__compare_3_3:
Define_entry(mercury__compare_3_3);
{
Code *compare_pred; /* address of the compare pred for this type */
int type_arity; /* number of type_info args */
@@ -448,7 +480,7 @@ mercury__compare_3_3:
** Since mod2c declares this label, we must define it,
** even though it is not needed with COMPACT_ARGS.
*/
mercury__compare_3_0_i1:
Define_label(mercury__compare_3_0_i1);
{
#ifdef COMPACT_ARGS
fatal_error("mercury__compare_3_0_i1 reached in COMPACT_ARGS mode");
@@ -462,5 +494,8 @@ mercury__compare_3_0_i1:
proceed();
#endif
}
END_MODULE
void mercury_sys_init_call(void); /* suppress gcc warning */
void mercury_sys_init_call(void) {
call_module();
}

68
runtime/mercury_imp.h Normal file
View File

@@ -0,0 +1,68 @@
/*
** Copyright (C) 1993-1997 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.
*/
/*
** imp.h - defines the interface to the Mercury abstract machine.
**
** IMPORTANT: this must be the *first* header file that is #included.
** It must come before any system header files. This is because on some
** systems, the system header files include inline functions, and this
** causes problems when using global register variables, as gcc requires
** global register variable declarations to precede any function definitions.
**
** This file just #includes most of the other Mercury runtime header files.
*/
#ifndef IMP_H
#define IMP_H
/*
** The #include of "mercury_conf.h" must come before the `#ifdef USE_DLLS',
** because mercury_conf.h defines the USE_DLLS macro.
*/
#include "mercury_conf.h"
/*
** The following must come before any definitions of global variables.
** This is necessary to support DLLs on Windows.
*/
#ifdef USE_DLLS
#include "libmer_dll.h"
#endif
#include "regs.h" /* must come before system headers */
#include "std.h"
#include "mercury_types.h"
#include "mercury_string.h"
#include "mercury_float.h"
#include "tags.h"
#include "goto.h"
#include "calls.h"
#include "engine.h"
#include "memory.h"
#include "heap.h"
#include "stacks.h"
#include "overflow.h"
#include "label.h"
#include "wrapper.h"
#include "context.h"
#include "type_info.h"
#ifdef MR_USE_TRAIL
#include "mercury_trail.h"
#endif
#include "debug.h"
#include "prof.h"
#include "misc.h"
#include "mercury_grade.h"
#endif /* not IMP_H */

102
runtime/mercury_init.h Normal file
View File

@@ -0,0 +1,102 @@
/*
** Copyright (C) 1993-1997 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.
*/
/*
** init.h - this file declares stuff defined in the automatically generated
** *_init.c files. This is also the interface used by C code that
** wishes to interface to Mercury.
**
** It also declares some stuff that is used in the automatically
** generate *_init.c files.
*/
#ifndef INIT_H
#define INIT_H
/*
** The following must come before any definitions of global variables.
** This is necessary to support DLLs on Windows.
*/
#include "mercury_conf.h" /* for USE_DLLS */
#if USE_DLLS
#include "libmer_dll.h"
#endif
/*---------------------------------------------------------------------------*/
/*
** This part is the interface that should be used by C programs that wish
** to interface to Mercury.
*/
/*
** mercury_main() is defined in the <module>_init.c file.
** It calls mercury_init(), mercury_call_main(), and then mercury_terminate().
*/
extern int mercury_main(int argc, char **argv);
/*
** mercury_init() is defined in the <module>_init.c file.
**
** The `argc' and `argv' parameters are as for main() in C.
** The `stack_bottom' parameter should be the address of a variable
** on the C stack. The conservative garbage collector treats that
** address as the start of the stack, so anything older than that
** address won't get scanned; don't store pointers to GC'ed memory
** in local variables that are older than that.
**
** mercury_init() just does some stuff to initialize the garbage
** collector, sets some global variables, and then calls
** mercury_runtime_init().
*/
extern void mercury_init(int argc, char **argv, char *stack_bottom);
/*
** mercury_call_main() is defined in the <module>_init.c file.
** It just calls mercury_runtime_main(), which calls main/2
** in the Mercury program.
*/
extern void mercury_call_main(void);
/*
** mercury_terminate() is defined in the <module>_init.c file.
** It just calls mercury_runtime_terminate(), which performs
** any necessary cleanup, and then returns the appropriate
** exit status as set by io__set_exit_status.
*/
extern int mercury_terminate(void);
/*---------------------------------------------------------------------------*/
/*
** This part defines things which are used by the automatically
** generated *_init.c file. These should not be used (directly)
** by C programs that wish to interface to Mercury.
*/
#include "goto.h" /* for Declare_entry */
#include "mercury_types.h" /* for `Word' */
#include "wrapper.h" /* for do_init_modules,
mercury_runtime_init(),
mercury_runtime_main(),
mercury_runtime_terminate(),
etc. */
#ifdef CONSERVATIVE_GC
#include "gc.h"
#endif
/*
** mercury_main() takes the address of the following predicates/functions,
** which are defined elsewhere.
*/
Declare_entry(mercury__main_2_0); /* in the user's program */
extern void mercury_init_io(void); /* in the Mercury library */
extern void ML_io_init_state(void); /* in the Mercury library */
extern void ML_io_finalize_state(void); /* in the Mercury library */
#endif /* not INIT_H */
/*---------------------------------------------------------------------------*/

View File

@@ -12,7 +12,7 @@
#include <stdio.h>
#include <string.h>
#include "conf.h"
#include "mercury_conf.h"
#include "label.h"

33
runtime/mercury_label.h Normal file
View File

@@ -0,0 +1,33 @@
/*
** Copyright (C) 1994-1997 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.
*/
/*
** label.h defines the interface to the label table, which is a pair of
** hash tables mapping from procedure names to addresses and vice versa.
*/
#ifndef LABEL_H
#define LABEL_H
#include "mercury_types.h" /* for `Code *' */
#include "dlist.h" /* for `List' */
typedef struct s_label {
const char *e_name; /* name of the procedure */
Code *e_addr; /* address of the code */
} Label;
extern void do_init_entries(void);
extern Label *insert_entry(const char *name, Code *addr);
extern Label *lookup_label_name(const char *name);
extern Label *lookup_label_addr(const Code *addr);
extern List *get_all_labels(void);
extern int entry_table_size;
/* expected number of entries in the table */
/* we allocate 8 bytes per entry */
#endif /* not LABEL_H */

View File

@@ -33,7 +33,7 @@
#include "libmer_dll.h"
#endif
#include "regs.h" /* must come first, due to global register vars */
#include "conf.h" /* must come second */
#include "mercury_conf.h" /* must come second */
#ifdef HAVE_SIGCONTEXT_STRUCT
/*

234
runtime/mercury_memory.h Normal file
View File

@@ -0,0 +1,234 @@
/*
** Copyright (C) 1994-1997 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.
*/
/*
** memory.h - general memory-allocation related stuff for the Mercury runtime.
**
** This defines the different memory areas used by the Mercury runtime,
** including the det & nondet stacks, the heap (and solutions heap),
** and the fake_reg array for holding Mercury virtual registers.
** It also provides interfaces for constructing new memory zones,
** and for allocating (possibly shared) memory.
*/
#ifndef MEMORY_H
#define MEMORY_H
#include "regs.h" /* for NUM_REAL_REGS */
#include <stdlib.h> /* for size_t */
#include "mercury_types.h" /* for Word */
#include "std.h" /* for bool */
/* these cannot be changed without lots of modifications elsewhere */
#define MAX_REAL_REG 32 /* r1 .. r32 */
#define NUM_SPECIAL_REG 5 /* succip, sp, hp, maxfr, curfr */
/* this can be changed at will, including by -D options to the C compiler */
#ifndef MAX_VIRTUAL_REG
#define MAX_VIRTUAL_REG 1024
#endif
/* allocate enough fake_regs to hold both the special regs */
/* and all the virtual registers */
#define MAX_FAKE_REG (NUM_SPECIAL_REG + MAX_VIRTUAL_REG)
/* mr0 .. mr36, mr(37) ... mr(1028) */
/* reserve MAX_FAKE_REG virtual regs, numbered from 0 to MAX_FAKE_REG-1 */
extern Word fake_reg[MAX_FAKE_REG];
/* used to lookup the fake_reg for a given real reg */
extern Word virtual_reg_map[MAX_REAL_REG];
/* used for counting register usage */
extern unsigned long num_uses[MAX_RN];
/*
** The Mercury runtime uses a number of memory areas or *zones*. These
** hold the detstack, the nondetstack, the heap, and potentially other
** areas such as a trail, a "solutions"-heap, and so on.
** These memory areas are each represented by a structure that contains
** the following fields:
** name - a string constant used to name the allocated area
** id - an integer which together with the name should uniquely
** identify the allocated area.
** bottom - the address of the bottom of the allocated area
** (should be on a page boundary)
** top - the address one word past the top of the allocated area
** (should be on a page boundary)
** min - the address of the lowest part of the allocated that
** will be used. This may be different to `bottom'
** so that the use of different memory zones doesn't
** beat the cache.
** max - the highest address in this memory area that has been
** used so far. This is only defined in debugging grades.
** hardmax - the address of the bottom of the last page of the allocated
** area. This is one higher than the highest address that
** can be used in this zone. We never unprotect the
** last page of a zone so that we retain protection
** against overrunning the end of the zone. This is
** obviously only available on platforms that have
** mprotect.
** (should be on a page boundary)
** redzone - the address of the start of the region that has been
** mprotected as a redzone. Since without SIGINFO
** it is not possible [portably] to figure out
** where the fault occured, redzone is only available
** on platforms that have both mprotect and SIGINFO.
** (should be on a page boundary)
** handler - the address of a function to handle accesses in the
** redzone of this allocated area. This is only
** specified if mprotect and SIGINFO are available.
*/
typedef struct MEMORY_ZONE MemoryZone;
typedef bool ZoneHandler(Word *addr, struct MEMORY_ZONE *zone, void *context);
struct MEMORY_ZONE {
struct MEMORY_ZONE *next; /* the memory zones are organized as a
** linked list of free zones and linked
** list of used zones. The next field
** is NULL or a pointer to the next memory
** zone in the list.
*/
const char *name; /* name identifier */
int id; /* number */
Word *bottom; /* beginning of the allocated area */
Word *top; /* end of the allocated area */
Word *min; /* lowest word of the area to be used */
#ifndef SPEED
Word *max; /* highest word of the area to be used */
#endif
#ifdef HAVE_MPROTECT
Word *redzone_base; /* beginning of the original redzone */
Word *redzone; /* beginning of the current redzone */
Word *hardmax; /* last page of the zone which can't be
unprotected */
#ifdef HAVE_SIGINFO
ZoneHandler *handler; /* handler for page faults in the redzone */
#endif /* HAVE_SIGINFO */
#endif /* HAVE_MPROTECT */
};
#define MAX_ZONES 16
extern MemoryZone *zone_table;
/* A linked list of all the unused zones */
extern MemoryZone *free_memory_zones;
/* A linked list of all the used zones */
extern MemoryZone *used_memory_zones;
extern MemoryZone *detstack_zone;
extern MemoryZone *nondetstack_zone;
#ifndef CONSERVATIVE_GC
extern MemoryZone *heap_zone;
extern MemoryZone *solutions_heap_zone;
#endif
#ifndef SPEED
extern MemoryZone *dumpstack_zone;
extern int dumpindex;
#endif
/*
** create_zone(Name, Id, Size, Offset, RedZoneSize, FaultHandler)
** allocates a new memory zone with name Name, and number Id, size
** Size (in bytes - which gets rounded up to the nearest multiple of
** the page size), an offset Offset from the page boundary at which
** to start using the memory region (used to help avoid beating the cache),
** the amount Redzone of memory (in bytes) to be protected as a redzone
** (must be less than Size), and the address of a function to handle
** memory references in the redzone.
** If it fails to allocate or protect the zone, then it exits.
** If mprotect or SIGINFO are unavailable, then the last two arguments
** are ignored.
*/
MemoryZone *create_zone(const char *name, int id,
size_t size, size_t offset, size_t redsize,
ZoneHandler *handler);
/*
** construct_zone(Name, Id, Base, Size, Offset, RedZoneSize, FaultHandler)
** has the same behaviour as create_zone, except instread of allocating
** the memory, it takes a pointer to a region of memory that must be at
** least Size bytes, or if HAVE_MPROTECT is defined, then it must be at
** least Size + unit[*] bytes.
** If it fails to protect the redzone then it exits
** If mprotect or SIGINFO are unavailable, then the last two arguments
** are ignored.
**
** [*] unit is a global variable containing the page size in bytes
*/
MemoryZone *construct_zone(const char *name, int Id, Word *base,
size_t size, size_t offset, size_t redsize,
ZoneHandler *handler);
/*
** reset_zone(Zone) resets the redzone on the given MemoryZone to the
** original zone specified in the call to {create,construct}_zone() if
** HAVE_MPROTECT and HAVE_SIGINFO. If either HAVE_MPROTECT or HAVE_SIGINFO
** are not defined, it does nothing.
*/
void reset_zone(MemoryZone *zone);
/*
** default_handler is a function that can be passed to create_zone to
** unprotect enough of the redzone to allow the access to succeed, or
** fail if there is no space left in the zone.
*/
ZoneHandler default_handler;
/*
** null_handler is a function that can be passed to create_zone which always
** fails.
*/
ZoneHandler null_handler;
/* for these functions, see the comments in memory.c and engine.mod */
extern void init_memory(void);
extern void init_heap(void);
extern void debug_memory(void);
/*
** next_offset() returns sucessive offsets across the primary cache. Useful
** when calling {create,construct}_zone().
*/
extern size_t next_offset(void);
/*
** allocate_bytes() allocates the given number of bytes.
**
** allocate_object(type) allocates space for an object of the specified type.
**
** allocate_array(type, num) allocates space for an array of objects of the
** specified type.
**
** If shared memory is being used, these allocation routines will allocate
** in shared memory.
*/
extern void *allocate_bytes(size_t numbytes);
#define allocate_object(type) \
((type *)allocate_bytes(sizeof(type)))
#define allocate_array(type, num) \
((type *)allocate_bytes((num) * sizeof(type)))
/*
** deallocate_memory() deallocates the memory allocated by one of the
** allocate_* functions.
*/
void deallocate_memory(void *);
#endif /* not MEMORY_H */

70
runtime/mercury_misc.h Normal file
View File

@@ -0,0 +1,70 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* misc.h - debugging messages, fatal_error(), and checked_malloc() */
#ifndef MISC_H
#define MISC_H
#include "mercury_types.h" /* for `Code *' */
#ifndef SPEED
extern void mkframe_msg(void);
extern void modframe_msg(void);
extern void succeed_msg(void);
extern void succeeddiscard_msg(void);
extern void fail_msg(void);
extern void redo_msg(void);
extern void call_msg(/* const */ Code *proc, /* const */ Code *succcont);
extern void tailcall_msg(/* const */ Code *proc);
extern void proceed_msg(void);
extern void cr1_msg(Word val0, const Word *addr);
extern void cr2_msg(Word val0, Word val1, const Word *addr);
extern void incr_hp_msg(Word val, const Word *addr);
extern void incr_sp_msg(Word val, const Word *addr);
extern void decr_sp_msg(Word val, const Word *addr);
extern void push_msg(Word val, const Word *addr);
extern void pop_msg(Word val, const Word *addr);
#endif
#if !defined(SPEED) || defined(DEBUG_GOTOS)
extern void goto_msg(/* const */ Code *addr);
extern void reg_msg(void);
#endif
#ifndef SPEED
extern void printint(Word n);
extern void printstring(const char *s);
extern void printheap(const Word *h);
extern void printdetstack(const Word *s);
extern void printnondstack(const Word *s);
extern void dumpframe(/* const */ Word *);
extern void dumpnondstack(void);
extern void printlist(Word p);
extern void printframe(const char *);
extern void printregs(const char *msg);
#endif
extern void printlabel(/* const */ Code *w);
#if __GNUC__
#define NO_RETURN __attribute__((noreturn))
#else
#define NO_RETURN
#endif
extern void fatal_error(const char *msg) NO_RETURN;
/* XXX checked_malloc() should be moved to memory.h or heap.h */
#include <stddef.h> /* for size_t */
void *checked_malloc(size_t n);
#endif /* not MISC_H */

View File

@@ -0,0 +1,78 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* overflow.h - definitions for overflow checks */
#ifndef OVERFLOW_H
#define OVERFLOW_H
#define IF(cond, val) ((cond) ? ((val), (void)0) : (void)0)
#ifdef SPEED
#define heap_overflow_check() ((void)0)
#define detstack_overflow_check() ((void)0)
#define detstack_underflow_check() ((void)0)
#define nondstack_overflow_check() ((void)0)
#define nondstack_underflow_check() ((void)0)
#else /* not SPEED */
#include "regs.h"
#include "misc.h" /* for fatal_error() */
#define heap_overflow_check() \
( \
IF (MR_hp >= heap_zone->top,( \
fatal_error("heap overflow") \
)), \
IF (MR_hp > heap_zone->max,( \
heap_zone->max = MR_hp \
)), \
(void)0 \
)
#define detstack_overflow_check() \
( \
IF (MR_sp >= detstack_zone->top,( \
fatal_error("stack overflow") \
)), \
IF (MR_sp > detstack_zone->max,( \
detstack_zone->max = MR_sp \
)), \
(void)0 \
)
#define detstack_underflow_check() \
( \
IF (MR_sp < detstack_zone->min,( \
fatal_error("stack underflow") \
)), \
(void)0 \
)
#define nondstack_overflow_check() \
( \
IF (MR_maxfr >= nondetstack_zone->top,( \
fatal_error("nondetstack overflow") \
)), \
IF (MR_maxfr > nondetstack_zone->max,( \
nondetstack_zone->max = MR_maxfr \
)), \
(void)0 \
)
#define nondstack_underflow_check() \
( \
IF (MR_maxfr < nondetstack_zone->min,( \
fatal_error("nondetstack underflow") \
)), \
(void)0 \
)
#endif /* not SPEED */
#endif /* not OVERFLOW_H */

49
runtime/mercury_prof.h Normal file
View File

@@ -0,0 +1,49 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* prof.h -- definitions for profiling */
#ifndef PROF_H
#define PROF_H
#include "mercury_types.h" /* for `Code *' */
/*
** this variable holds the address of the "current" procedure so that
** when a profiling interrupt occurs, the profiler knows where we are,
** so that it can credit the time to the appropriate procedure.
*/
extern Code * volatile prof_current_proc;
/*
** the following two macros are used to ensure that the profiler can
** use `prof_current_proc' to determine what procedure is currently
** being executed when a profiling interrupt occurs
*/
#ifdef PROFILE_TIME
#define set_prof_current_proc(target) (prof_current_proc = (target))
#define update_prof_current_proc(target) (prof_current_proc = (target))
#else
#define set_prof_current_proc(target) ((void)0)
#define update_prof_current_proc(target) ((void)0)
#endif
#ifdef PROFILE_CALLS
#define PROFILE(callee, caller) prof_call_profile((callee), (caller))
#else
#define PROFILE(callee, caller) ((void)0)
#endif
extern void prof_init_time_profile(void);
extern void prof_call_profile(Code *, Code *);
extern void prof_turn_off_time_profiling(void);
extern void prof_output_addr_pair_table(void);
extern void prof_output_addr_decls(const char *, const Code *);
extern void prof_output_addr_table(void);
#endif /* not PROF_H */

View File

@@ -0,0 +1,30 @@
/*
** Copyright (C) 1996-1997 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.
*/
/*
** prof_mem.h - defines memory allocation functions used to hold
** the tables of profiling counts.
**
** Author: petdr
*/
#ifndef PROF_MEM_H
#define PROF_MEM_H
#include <stddef.h> /* for size_t */
/*
** prof_malloc() allocates memory in large chunks using newmem(),
** and then doles out portions of these chunks one at a time.
** We use prof_malloc() to reduce the chance of calling newmem()
** from a profiling interrupt that interrupted another call to newmem().
** Doing that is bad news, because newmem() is not re-entrant.
*/
void *prof_malloc(size_t);
#define prof_make(t) ((t *) prof_malloc(sizeof(t)))
#endif /* not PROF_MEM_H */

112
runtime/mercury_regorder.h Normal file
View File

@@ -0,0 +1,112 @@
/*
** Copyright (C) 1994-1995, 1997 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.
*/
/*
** regorder.h - defines the mapping from the Mercury abstract machine
** registers (r1, r2, ..., hp, sp, etc.) to the underlying intermediate-level
** abstract machine memory (mr0, mr1, ...).
**
** This file should be #included from "regs.h" and nowhere else.
** The reason this is separate from "regs.h" is so that it could,
** at least in theory, be generated automatically based on
** profiling feedback from the register usage counts for a particular
** application. However, currently we don't do that.
**
** If you change this file, you should also change the settings of
** NUM_REAL_R_REGS in ../configure.in.
*/
#ifndef REGORDER_H
#define REGORDER_H
#define r1 count_usage(R_RN(1), mr2)
#define r2 count_usage(R_RN(2), mr3)
#define r3 count_usage(R_RN(3), mr4)
#define r4 count_usage(R_RN(4), mr6)
#define r5 count_usage(R_RN(5), mr7)
#define r6 count_usage(R_RN(6), mr10)
#define r7 count_usage(R_RN(7), mr11)
#define r8 count_usage(R_RN(8), mr12)
#define r9 count_usage(R_RN(9), mr13)
#define r10 count_usage(R_RN(10), mr14)
#define r11 count_usage(R_RN(11), mr15)
#define r12 count_usage(R_RN(12), mr16)
#define r13 count_usage(R_RN(13), mr17)
#define r14 count_usage(R_RN(14), mr18)
#define r15 count_usage(R_RN(15), mr19)
#define r16 count_usage(R_RN(16), mr20)
#define r17 count_usage(R_RN(17), mr21)
#define r18 count_usage(R_RN(18), mr22)
#define r19 count_usage(R_RN(19), mr23)
#define r20 count_usage(R_RN(20), mr24)
#define r21 count_usage(R_RN(21), mr25)
#define r22 count_usage(R_RN(22), mr26)
#define r23 count_usage(R_RN(23), mr27)
#define r24 count_usage(R_RN(24), mr28)
#define r25 count_usage(R_RN(25), mr29)
#define r26 count_usage(R_RN(26), mr30)
#define r27 count_usage(R_RN(27), mr31)
#define r28 count_usage(R_RN(28), mr32)
#define r29 count_usage(R_RN(29), mr33)
#define r30 count_usage(R_RN(30), mr34)
#define r31 count_usage(R_RN(31), mr35)
#define r32 count_usage(R_RN(32), mr36)
#define MR_succip LVALUE_CAST(Code *, count_usage(MR_SI_RN, mr1))
#define succip MR_succip
#define MR_hp LVALUE_CAST(Word *, count_usage(MR_HP_RN, mr5))
#define hp MR_hp
#define MR_sp LVALUE_CAST(Word *, count_usage(MR_SP_RN, mr0))
#define sp MR_sp
#define MR_curfr LVALUE_CAST(Word *, count_usage(MR_CF_RN, mr8))
#define curfr MR_curfr
#define MR_maxfr LVALUE_CAST(Word *, count_usage(MR_MF_RN, mr9))
#define maxfr MR_maxfr
#define MR_sol_hp LVALUE_CAST(Word *, count_usage(MR_SOL_HP_RN, mr(37)))
#define MR_min_hp_rec LVALUE_CAST(Word *, count_usage(MR_MIN_HP_REC, mr(38)))
#define MR_min_sol_hp_rec LVALUE_CAST(Word *, \
count_usage(MR_MIN_HP_REC, mr39))
#define MR_trail_ptr count_usage(MR_TRAIL_PTR_RN, MR_trail_ptr_var)
#define MR_ticket_counter \
count_usage(MR_TICKET_COUNTER_RN, MR_ticket_counter_var)
#define VIRTUAL_REG_MAP_BODY { \
2, \
3, \
4, \
6, \
7, \
10, \
11, \
12, \
13, \
14, \
15, \
16, \
17, \
18, \
19, \
20, \
21, \
22, \
23, \
24, \
25, \
26, \
27, \
28, \
29, \
30, \
31, \
32, \
33, \
34, \
35, \
36, \
}
#endif /* not REGORDER_H */

165
runtime/mercury_regs.h Normal file
View File

@@ -0,0 +1,165 @@
/*
** Copyright (C) 1993-1997 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.
*/
#ifndef REGS_H
#define REGS_H
#include "mercury_conf.h"
#include "mercury_types.h"
/*
** GNU C allows lvalue casts, so if we have gcc, use them.
** If we don't have gcc, then we can use *(type *)&lval,
** but that wouldn't work for gcc since lval might be a global
** register in which case we couldn't take it's address.
** Similarly for comma expressions and conditional expressions.
*/
#ifdef __GNUC__
#define LVALUE_CAST(type, lval) ((type)(lval))
#define LVALUE_SEQ(expr, lval) ((expr),(lval))
#define LVALUE_COND(expr, x, y) ((expr)?(x):(y))
#else
#define LVALUE_CAST(type, lval) (*(type*)&(lval))
#define LVALUE_SEQ(expr, lval) (*((expr),&(lval)))
#define LVALUE_COND(expr, x, y) (*((expr)?&(x):&(y)))
#endif
/*
** The registers of the Mercury virtual machine are built up using
** three levels of abstraction.
**
** The first level defines the first NUM_REAL_REGS register variables
** mr0, mr1, etc. as the physical machine registers, and defines an
** array fake_regs[n] of pseudo registers.
**
** The next level defines macros mr0 through mr36 and also mr(n) for
** n>36. The lower the number,
** the greater the probability that the storage referred to will be
** a real machine register, and not a simulated one. The number of
** real machine registers is given by the macro NUM_REAL_REGS.
**
** The final level maps the Mercury virtual machine registers
**
** succip, hp, sp, curfr, maxfr and
** r1, ..., r32, r(33), ..., r(MAX_VIRTUAL_REG)
**
** to the set mr0..mr36, mr(37), mr(38), ..., mr(MAX_FAKE_REG-1)
**
** Since the set of most frequently used Mercury virtual machine
** registers can be different for each program, we want to make
** this mapping as easy to change as possible. This is why the
** map is in a minimal header file, regorder.h.
*/
#if defined(USE_GCC_GLOBAL_REGISTERS)
#ifndef __GNUC__
#error "You must use gcc if you define USE_GCC_GLOBAL_REGISTERS."
#endif
#if defined(__mips__)
#include "machdeps/mips_regs.h"
#elif defined(__i386__)
#include "machdeps/i386_regs.h"
#elif defined(__sparc__)
#include "machdeps/sparc_regs.h"
#elif defined(__alpha__)
#include "machdeps/alpha_regs.h"
#elif defined(__hppa__)
#include "machdeps/pa_regs.h"
#elif defined(_POWER)
#include "machdeps/rs6000_regs.h"
#else
#error "USE_GCC_GLOBAL_REGISTERS not yet supported on this machine."
#endif
#else
#include "machdeps/no_regs.h"
#endif
/* The machdeps header defines mr0 .. mr36; now define mr(n) for n > 36 */
#define mr(n) LVALUE_SEQ(MR_assert((n) >= MAX_REAL_REG + NUM_SPECIAL_REG && \
(n) < MAX_FAKE_REG),\
fake_reg[n])
#ifdef MEASURE_REGISTER_USAGE
#define count_usage(num,reg) LVALUE_SEQ(num_uses[num]++, reg)
#else
#define count_usage(num,reg) (reg)
#endif
#include "regorder.h"
/* regorder.h defines r1 .. r32; now define r(n) for n > 32 */
#define r(n) mr((n) + NUM_SPECIAL_REG - 1)
/*
** the save_registers() macro copies the physical machine registers
** to their corresponding slots in the fake_reg array
*/
#define save_registers() save_regs_to_mem(fake_reg)
/*
** the restore_registers() macro sets the physical machine registers
** to the values in their corresponding slots in the fake_reg array
*/
#define restore_registers() restore_regs_from_mem(fake_reg)
/*
** the save_transient_registers() and restore_transient_registers()
** macros are similar to save_registers() and restore_registers()
** except that they only save/restore registers which can be
** affected by calling or returning from a C function (e.g.
** by sliding register windows on SPARCs).
*/
#define save_transient_registers() save_transient_regs_to_mem(fake_reg)
#define restore_transient_registers() restore_transient_regs_from_mem(fake_reg)
/* virtual_reg(n) accesses the underlying fake_reg for register n */
#define virtual_reg(n) \
LVALUE_COND((n) > MAX_REAL_REG, \
r(n), \
fake_reg[virtual_reg_map[(n) - 1]])
/*
** get_reg() and set_reg() provide a different way of addressing
** the registers; unlike virtual_reg(), you don't need to wrap them
** inside save_registers()/restore_regs() to copy the real regs to/from
** the fake_reg, so they may perhaps be more efficient if you are just
** getting or setting one or two registers?
** Currently they're buggy for n>32 and are not used except for debugging.
*/
extern Word get_reg(int);
extern Word set_reg(int, Word);
/*
** the following macros define a mapping from registers to indices into the
** num_uses array used for counting register usage
**
** any changes to these will also require changes to
** print_register_usage_counts() in wrapper.mod.
*/
#define MR_SI_RN 0
#define MR_R_RN(n) (n)
#define MR_ORD_RN MAX_REAL_REG
#define MR_HP_RN (MR_ORD_RN + 1)
#define MR_SP_RN (MR_ORD_RN + 2)
#define MR_CF_RN (MR_ORD_RN + 3)
#define MR_MF_RN (MR_ORD_RN + 4)
#define MR_TRAIL_PTR_RN (MR_ORD_RN + 5)
#define MR_TICKET_COUNTER_RN (MR_ORD_RN + 6)
#define MR_SOL_HP_RN (MR_ORD_RN + 7)
#define MR_MIN_HP_REC (MR_ORD_RN + 8)
#define MR_MIN_SOL_HP_REC (MR_ORD_RN + 9)
#define MAX_RN (MR_ORD_RN + 10)
#endif /* not REGS_H */

View File

@@ -0,0 +1,90 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* spinlock.h - defines spin locks (locks obtained by busy-waiting) */
#ifndef SPINLOCK_H
#define SPINLOCK_H
/*
** This part of the header file documents the abstract interface for a spinlock.
*/
#if 0 /* everything here is really implemented as macros */
/*
** You can assume that a SpinLock will fit into a Word,
** i.e. that sizeof(SpinLock) <= sizeof(Word).
** But you should not assume anything else.
*/
typedef ... SpinLock;
/*
** allocate_lock() returns a pointer to a new initialized lock,
** allocated in shared memory.
** deallocate_lock() deinitializes and deallocates a lock.
*/
extern SpinLock *allocate_lock(void);
extern void deallocate_lock(SpinLock *);
/*
** get_lock() and release_lock() are used to
** acquire and relinquish a lock.
*/
void get_lock(SpinLock *);
void release_lock(SpinLock *);
#endif /* 0 */
/*---------------------------------------------------------------------------*/
/*
** The following are implementation details.
** They're defined here in the header file so that they can be inlined,
** but code elsewhere should avoid depending on these details.
*/
#include "mercury_types.h" /* for `SpinLock' and `Word' */
#include <stddef.h> /* for `NULL' */
#include "mercury_conf.h" /* for `PARALLEL' */
#include "context.h" /* for `numprocs' */
void do_spinlock(SpinLock *s);
void do_spinunlock(SpinLock *s);
#ifdef PARALLEL
#define get_lock(addr) do { \
if (numprocs != 1) { \
do_spinlock(addr); \
} \
} while(0)
#define release_lock(addr) do { \
if (numprocs != 1) { \
do_spinunlock(addr); \
} \
} while(0)
#define allocate_lock() allocate_object(SpinLock)
#define deallocate_lock(lock) deallocate(lock)
#else /* not PARALLEL */
#define get_lock(addr) do { } while (0)
#define release_lock(addr) do { } while (0)
#define allocate_lock() NULL
#define deallocate_lock(lock) do { } while(0)
#endif /* not PARALLEL */
#endif /* not SPINLOCK_H */

175
runtime/mercury_stacks.h Normal file
View File

@@ -0,0 +1,175 @@
/*
** Copyright (C) 1995-1997 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.
*/
/* stacks.h - definitions for manipulation the det and nondet stacks */
#ifndef STACKS_H
#define STACKS_H
#include "regs.h"
#include "mercury_types.h"
#include "overflow.h"
#include "debug.h"
#include "goto.h"
/* DEFINITIONS FOR MANIPULATING THE DET STACK */
#define detstackvar(n) (MR_sp[-n])
#define incr_sp_push_msg(n, msg) \
( \
debugincrsp(n, MR_sp), \
dump_push_msg(msg), \
MR_sp = MR_sp + (n), \
detstack_overflow_check(), \
(void)0 \
)
#define decr_sp_pop_msg(n) \
( \
debugdecrsp(n, MR_sp), \
dump_pop_msg(), \
MR_sp = MR_sp - (n), \
detstack_underflow_check(), \
(void)0 \
)
#define incr_sp(n) ( \
debugincrsp(n, MR_sp), \
MR_sp = MR_sp + (n), \
detstack_overflow_check(), \
(void)0 \
)
#define decr_sp(n) ( \
debugdecrsp(n, MR_sp), \
MR_sp = MR_sp - (n), \
detstack_underflow_check(), \
(void)0 \
)
#define push(w) ( \
*MR_sp = (Word) (w), \
debugpush(*sp, MR_sp), \
MR_sp = MR_sp + 1, \
detstack_overflow_check(), \
(void)0 \
)
#define pop() ( \
MR_sp = MR_sp - 1, \
debugpop(*MR_sp, MR_sp), \
detstack_underflow_check(), \
/* return */ *MR_sp \
)
/* DEFINITIONS FOR NONDET STACK FRAMES */
#define REDOIP (-0) /* in this proc, set up at clause entry */
#define PREVFR (-1) /* prev frame on stack, set up at call */
#define SUCCIP (-2) /* in caller proc, set up at call */
#define SUCCFR (-3) /* frame of caller proc, set up at call */
#ifdef SPEED
#define bt_prednm(fr) "unknown"
#define NONDET_FIXED_SIZE_0 4 /* units: words */
#else
#define PREDNM (-4) /* for debugging, set up at call */
#define bt_prednm(fr) LVALUE_CAST(const char *, ((Word *) fr)[PREDNM])
#define NONDET_FIXED_SIZE_0 5 /* units: words */
#endif
#define NONDET_FIXED_SIZE NONDET_FIXED_SIZE_0
#define SAVEVAL (-NONDET_FIXED_SIZE)
/* saved values start at this offset */
#define bt_redoip(fr) LVALUE_CAST(Code *, ((Word *) (fr))[REDOIP])
#define bt_prevfr(fr) LVALUE_CAST(Word *, ((Word *) (fr))[PREVFR])
#define bt_succip(fr) LVALUE_CAST(Code *, ((Word *) (fr))[SUCCIP])
#define bt_succfr(fr) LVALUE_CAST(Word *, ((Word *) (fr))[SUCCFR])
#define bt_var(fr,n) (((Word *) (fr))[SAVEVAL-(n)])
#define curprednm bt_prednm(MR_curfr)
#define curredoip bt_redoip(MR_curfr)
#define curprevfr bt_prevfr(MR_curfr)
#define cursuccip bt_succip(MR_curfr)
#define cursuccfr bt_succfr(MR_curfr)
#define framevar(n) bt_var(MR_curfr,n)
/* DEFINITIONS FOR MANIPULATING THE NONDET STACK */
#ifndef SPEED
#define mkframe_save_prednm(prednm) (curprednm = prednm)
#else
#define mkframe_save_prednm(prednm) /* nothing */
#endif
#define mkframe(prednm, numslots, redoip) \
do { \
reg Word *prevfr; \
reg Word *succfr; \
\
prevfr = MR_maxfr; \
succfr = MR_curfr; \
MR_maxfr += (NONDET_FIXED_SIZE + numslots);\
MR_curfr = MR_maxfr; \
curredoip = redoip; \
curprevfr = prevfr; \
cursuccip = MR_succip; \
cursuccfr = succfr; \
mkframe_save_prednm(prednm); \
debugmkframe(); \
nondstack_overflow_check(); \
} while (0)
#define modframe(redoip) \
do { \
curredoip = redoip; \
debugmodframe(); \
} while (0)
#define succeed() do { \
reg Word *childfr; \
\
debugsucceed(); \
childfr = MR_curfr; \
MR_curfr = cursuccfr; \
GOTO(bt_succip(childfr)); \
} while (0)
#define succeed_discard() \
do { \
reg Word *childfr; \
\
debugsucceeddiscard(); \
childfr = MR_curfr; \
MR_maxfr = curprevfr; \
MR_curfr = cursuccfr; \
GOTO(bt_succip(childfr)); \
} while (0)
#define fail() do { \
debugfail(); \
MR_maxfr = curprevfr; \
MR_curfr = MR_maxfr; \
nondstack_underflow_check(); \
GOTO(curredoip); \
} while (0)
#define redo() do { \
debugredo(); \
MR_curfr = MR_maxfr; \
GOTO(curredoip); \
} while (0)
#endif /* not STACKS_H */

68
runtime/mercury_std.h Normal file
View File

@@ -0,0 +1,68 @@
/*
** Copyright (C) 1993-1995, 1997 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.
*/
/*
** std.h - "standard" [sic] definitions for C:
** bool, TRUE, FALSE, min(), max(), streq(), etc.
*/
#ifndef STD_H
#define STD_H
#include <stdlib.h> /* for size_t */
#include <assert.h> /* for assert() */
#ifndef reg
#define reg register
#endif
#ifndef bool
#define bool char
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#define streq(s1, s2) (strcmp(s1, s2) == 0)
#define strdiff(s1, s2) (strcmp(s1, s2) != 0)
#define strtest(s1, s2) (strcmp(s1, s2))
#define strneq(s1, s2, n) (strncmp(s1, s2, n) == 0)
#define strndiff(s1, s2, n) (strncmp(s1, s2, n) != 0)
#define strntest(s1, s2, n) (strncmp(s1, s2, n))
#define ungetchar(c) ungetc(c, stdin)
/* XXX these should go in memory.h or heap.h */
#define make(t) ((t *) newmem(sizeof(t)))
#define make_many(t, n) ((t *) newmem((n) * sizeof(t)))
#define resize_many(t, p, n) ((t *) resizemem((p), (n) * sizeof(t)))
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*
** turn assertions off for speed
*/
#ifdef SPEED
#define MR_assert(ASSERTION) ((void)0)
#else
#define MR_assert(ASSERTION) assert(ASSERTION)
#endif
/* XXX these should go in memory.h or heap.h */
extern void *newmem(size_t);
extern void *resizemem(void *, size_t);
extern void oldmem(void *);
#endif /* not STD_H */

42
runtime/mercury_table.h Normal file
View File

@@ -0,0 +1,42 @@
/*
** Copyright (C) 1993-1995, 1997 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.
*/
/*
** table.h - defines the interface to the hash table module.
*/
#ifndef TABLE_H
#define TABLE_H
#include "std.h" /* for bool */
#include "dlist.h" /* for List */
typedef struct s_table {
int ta_size;
List **ta_store;
const void * (*ta_key)(const void *); /* applied to entries */
int (*ta_hash)(const void *); /* applied to keys */
bool (*ta_equal)(const void *, const void *);
/* applied to two keys */
} Table;
#define init_table(t) tab_init_table(&t)
#define lookup_table(t, k) tab_lookup_table(&t, (const void *) k)
#define insert_table(t, e) tab_insert_table(&t, (void *) e)
#define get_all_entries(t) tab_get_all_entries(&t)
#define str_to_int(val) tab_str_to_int(val)
#define tablekey(table) (*(table->ta_key))
#define tablehash(table) (*(table->ta_hash))
#define tableequal(table) (*(table->ta_equal))
extern void tab_init_table(Table *);
extern void * tab_lookup_table(const Table *, const void *);
extern bool tab_insert_table(const Table *, void *);
extern List *tab_get_all_entries(const Table *);
extern int tab_str_to_int(const char *);
#endif /* not TABLE_H */

110
runtime/mercury_tags.h Normal file
View File

@@ -0,0 +1,110 @@
/*
** Copyright (C) 1993-1997 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.
*/
/*
** tags.h - defines macros for tagging and untagging words.
** Also defines macros for accessing the Mercury list type from C.
*/
#ifndef TAGS_H
#define TAGS_H
#include <limits.h> /* for `CHAR_BIT' */
#include "mercury_conf.h" /* for `LOW_TAG_BITS' */
#include "mercury_types.h" /* for `Word' */
/* DEFINITIONS FOR WORD LAYOUT */
#define WORDBITS (CHAR_BIT * sizeof(Word))
/* TAGBITS specifies the number of bits in each word that we can use for tags */
#ifndef TAGBITS
#ifdef HIGHTAGS
#error "HIGHTAGS defined but TAGBITS undefined"
#else
#define TAGBITS LOW_TAG_BITS
#endif
#endif
#if TAGBITS > 0 && defined(HIGHTAGS) && defined(CONSERVATIVE_GC)
#error "Conservative GC does not work with high tag bits"
#endif
#ifdef HIGHTAGS
#define mktag(t) ((Word)(t) << (WORDBITS - TAGBITS))
#define unmktag(w) ((Word)(w) >> (WORDBITS - TAGBITS))
#define tag(w) ((w) & ~(~(Word)0 >> TAGBITS))
#define mkbody(i) (i)
#define unmkbody(w) (w)
#define body(w, t) ((w) & (~(Word)0 >> TAGBITS))
#define strip_tag(w) ((w) & (~(Word)0 >> TAGBITS))
#else /* ! HIGHTAGS */
#define mktag(t) (t)
#define unmktag(w) (w)
#define tag(w) ((w) & ((1 << TAGBITS) - 1))
#define mkbody(i) ((i) << TAGBITS)
#define unmkbody(w) ((Word) (w) >> TAGBITS)
#define body(w, t) ((w) - (t))
#define strip_tag(w) ((w) & (~(Word)0 << TAGBITS))
#endif /* ! HIGHTAGS */
/*
** the result of mkword() is cast to (const Word *), not to (Word)
** because mkword() may be used in initializers for static constants
** and casts from pointers to integral types are not valid
** constant-expressions in ANSI C.
*/
#define mkword(t, p) ((const Word *)((const char *)(p) + (t)))
#define field(t, p, i) ((Word *) body((p), (t)))[i]
#define const_field(t, p, i) ((const Word *) body((p), (t)))[i]
/*
** the following list_* macros are used by handwritten C code
** that needs to access Mercury lists.
*/
#define bTAG_NIL 0
#define bTAG_CONS 1
#define bTAG_VAR 3 /* for Prolog-style variables */
/* ... but currently not used */
#define TAG_NIL mktag(bTAG_NIL)
#define TAG_CONS mktag(bTAG_CONS)
#define TAG_VAR mktag(bTAG_VAR)
#if TAGBITS > 0
#define list_is_empty(list) (tag(list) == TAG_NIL)
#define list_head(list) field(TAG_CONS, (list), 0)
#define list_tail(list) field(TAG_CONS, (list), 1)
#define list_empty() ((Word) mkword(TAG_NIL, mkbody(0)))
#define list_cons(head,tail) \
((Word) mkword(TAG_CONS, create2((head),(tail))))
#else
#define list_is_empty(list) (field(mktag(0), (list), 0) == bTAG_NIL)
#define list_head(list) field(mktag(0), (list), 1)
#define list_tail(list) field(mktag(0), (list), 2)
#define list_empty() ((Word) mkword(mktag(0), create1(bTAG_NIL)))
#define list_cons(head,tail) \
((Word) mkword(mktag(0), create3(bTAG_CONS, (head), (tail))))
#endif
/* for Prolog-style variables... currently not used */
#define deref(pt) do { \
while (tag(pt) == TAG_VAR) \
(pt) = * (Word *) \
body((pt), TAG_VAR); \
} while(0)
#endif /* not TAGS_H */

47
runtime/mercury_timing.h Normal file
View File

@@ -0,0 +1,47 @@
/*
** Copyright (C) 1993-1995, 1997 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.
*/
/*
** timing.h - interface to timing routines.
** Defines `MR_CLOCK_TICKS_PER_SECOND'
** and `MR_get_user_cpu_miliseconds()'.
*/
#ifndef TIMING_H
#define TIMING_H
#include "mercury_conf.h"
#ifdef HAVE_SYS_PARAM
#include <sys/param.h> /* for HZ */
#endif
#include <unistd.h> /* for sysconf() and _SC_CLK_TCK */
#include <limits.h> /* CLK_TCK defined here, on some systems */
/*
** `HZ' is the number of clock ticks per second.
** It is used when converting a clock_t value to a time in seconds.
** It may be defined by <sys/time.h>, but if it is not defined there,
** we may be able to use `sysconf(_SC_CLK_TCK)' or CLK_TCK instead.
*/
#ifdef HZ
#define MR_CLOCK_TICKS_PER_SECOND HZ
#elif defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
#define MR_CLOCK_TICKS_PER_SECOND ((int) sysconf(_SC_CLK_TCK))
#elif defined(CLK_TCK)
#define MR_CLOCK_TICKS_PER_SECOND CLK_TCK
#else
/* just leave it undefined */
#endif
/*
** MR_get_user_cpu_miliseconds() returns the CPU time consumed by the
** process, in miliseconds, from an arbitrary initial time.
*/
int MR_get_user_cpu_miliseconds(void);
#endif /* TIMING_H */

View File

@@ -1,4 +1,8 @@
/*
INIT mercury_sys_init_type_info
ENDINIT
*/
/*
** Copyright (C) 1995-1997 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.
@@ -111,35 +115,47 @@ Define_extern_entry(mercury__builtin_index_pred_2_0);
Define_extern_entry(mercury__builtin_compare_pred_3_0);
Declare_label(mercury__builtin_compare_pred_3_0_i4);
BEGIN_MODULE(mercury__builtin_unify_pred_module)
Define_extern_entry(mercury__builtin_unify_pred_2_0);
BEGIN_MODULE(mercury__builtin_unify_pred_module)
init_entry(mercury__builtin_unify_pred_2_0);
BEGIN_CODE
/* code for predicate 'builtin_unify_pred'/2 in mode 0 */
mercury__builtin_unify_pred_2_0:
Define_entry(mercury__builtin_unify_pred_2_0);
incr_sp_push_msg(2, "mercury_builtin:builtin_unify_pred");
fatal_error("attempted unification of higher-order terms");
END_MODULE
BEGIN_MODULE(mercury__builtin_index_pred_module)
Define_extern_entry(mercury__builtin_index_pred_2_0);
BEGIN_MODULE(mercury__builtin_index_pred_module)
init_entry(mercury__builtin_index_pred_2_0);
BEGIN_CODE
/* code for predicate 'builtin_index_pred'/2 in mode 0 */
mercury__builtin_index_pred_2_0:
Define_entry(mercury__builtin_index_pred_2_0);
r1 = (Integer) -1;
proceed();
END_MODULE
BEGIN_MODULE(mercury__builtin_compare_pred_module)
Define_extern_entry(mercury__builtin_compare_pred_3_0);
BEGIN_MODULE(mercury__builtin_compare_pred_module)
init_entry(mercury__builtin_compare_pred_3_0);
BEGIN_CODE
/* code for predicate 'builtin_compare_pred'/3 in mode 0 */
mercury__builtin_compare_pred_3_0:
Define_entry(mercury__builtin_compare_pred_3_0);
incr_sp_push_msg(2, "mercury_builtin:builtin_compare_pred");
fatal_error("attempted comparison of higher-order terms");
END_MODULE
/*---------------------------------------------------------------------------*/
void mercury_sys_init_type_info(void); /* suppress gcc warning */
void mercury_sys_init_type_info(void) {
mercury__builtin_unify_pred_module();
mercury__builtin_index_pred_module();
mercury__builtin_compare_pred_module();
}

788
runtime/mercury_type_info.h Normal file
View File

@@ -0,0 +1,788 @@
/*
** Copyright (C) 1995-1997 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.
*/
/*
** type_info.h -
** Definitions for accessing the type_infos, type_layouts, and
** type_functors tables generated by the Mercury compiler.
** Also contains definitions for accessing the Mercury `univ' type
** and the Mercury `array' type.
*/
#ifndef TYPE_INFO_H
#define TYPE_INFO_H
#include "mercury_types.h" /* for `Word' */
/*---------------------------------------------------------------------------*/
/*
** Decide which type_info representation we will use.
**
** At present, only SHARED_ONE_OR_TWO_CELL_TYPE_INFO is available.
**
*/
#define SHARED_ONE_OR_TWO_CELL_TYPE_INFO
/*---------------------------------------------------------------------------*/
/*
** Define offsets of fields in the base_type_info or type_info structure.
** See polymorphism.m for explanation of these offsets and how the
** type_info and base_type_info structures are laid out.
**
** ANY CHANGES HERE MUST BE MATCHED BY CORRESPONDING CHANGES
** TO THE DOCUMENTATION IN compiler/polymorphism.m.
**
** The one_or_two_cell type_info representation
** *depends* on OFFSET_FOR_COUNT being 0.
*/
#define OFFSET_FOR_COUNT 0
#define OFFSET_FOR_UNIFY_PRED 1
#define OFFSET_FOR_INDEX_PRED 2
#define OFFSET_FOR_COMPARE_PRED 3
#define OFFSET_FOR_BASE_TYPE_LAYOUT 4
#define OFFSET_FOR_BASE_TYPE_FUNCTORS 5
#define OFFSET_FOR_TYPE_MODULE_NAME 6
#define OFFSET_FOR_TYPE_NAME 7
/*
** Define offsets of fields in the type_info structure.
*/
#define OFFSET_FOR_ARG_TYPE_INFOS 1
/*
** Where the predicate arity and args are stored in the type_info.
** For one-or-two-cell, they are stored in the type_info (*not* the
** base_type_info).
** This is brought about by higher-order predicates all using the
** same base_type_info - pred/0.
** For one-cell, the arity is at the same offset as the count.
*/
#define TYPEINFO_OFFSET_FOR_PRED_ARITY 1
#define TYPEINFO_OFFSET_FOR_PRED_ARGS 2
/*---------------------------------------------------------------------------*/
/*
** Definitions for handwritten code, mostly for mercury_compare_typeinfo.
*/
#define COMPARE_EQUAL 0
#define COMPARE_LESS 1
#define COMPARE_GREATER 2
#ifdef COMPACT_ARGS
#define mercury__unify__typeinfo r1
#define mercury__unify__x r2
#define mercury__unify__y r3
#define mercury__unify__offset 0
#define mercury__compare__typeinfo r1
#define mercury__compare__x r2
#define mercury__compare__y r3
#define mercury__compare__offset 0
#define mercury__term_to_type__typeinfo r1
#define mercury__term_to_type__term r2
#define mercury__term_to_type__x r4
#define mercury__term_to_type__offset 1
#define unify_input1 r1
#define unify_input2 r2
#define unify_output r1
#define compare_input1 r1
#define compare_input2 r2
#define compare_output r1
#define index_input r1
#define index_output r1
#else
#define mercury__unify__typeinfo r2
#define mercury__unify__x r3
#define mercury__unify__y r4
#define mercury__unify__offset 1
#define mercury__compare__typeinfo r1
#define mercury__compare__x r3
#define mercury__compare__y r4
#define mercury__compare__offset 1
#define mercury__term_to_type__typeinfo r2
#define mercury__term_to_type__term r3
#define mercury__term_to_type__x r4
#define mercury__term_to_type__offset 1
#define unify_input1 r2
#define unify_input2 r3
#define unify_output r1
#define compare_input1 r2
#define compare_input2 r3
#define compare_output r1
#define index_input r1
#define index_output r2
#endif
/*---------------------------------------------------------------------------*/
/*
** Definitions and macros for base_type_layout definition.
**
** See compiler/base_type_layout.m for more information.
**
** If we don't have enough tags, we have to encode layouts
** less densely. The make_typelayout macro does this, and
** is intended for handwritten code. Compiler generated
** code can (and does) just create two rvals instead of one.
**
*/
/*
** Conditionally define USE_TYPE_LAYOUT.
**
** All code using type_layout structures should check to see if
** USE_TYPE_LAYOUT is defined, and give a fatal error otherwise.
** For USE_TYPE_LAYOUT to be defined, we need to be using
** shared one-or-two cell type_infos (since the type_layouts refer
** to base_type_layouts). USE_TYPE_LAYOUT can be explicitly turned
** off with NO_TYPE_LAYOUT.
**
*/
#if defined(SHARED_ONE_OR_TWO_CELL_TYPE_INFO) && !defined(NO_TYPE_LAYOUT)
#define USE_TYPE_LAYOUT
#else
#undef USE_TYPE_LAYOUT
#endif
/*
** Code intended for defining type_layouts for handwritten code.
**
** See library/io.m or library/mercury_builtin.m for details.
*/
#if TAGBITS >= 2
typedef const Word *TypeLayoutField;
#define TYPE_LAYOUT_FIELDS \
TypeLayoutField f1,f2,f3,f4,f5,f6,f7,f8;
#define make_typelayout(Tag, Value) \
mkword(mktag(Tag), (Value))
#else
typedef const Word *TypeLayoutField;
#define TYPE_LAYOUT_FIELDS \
TypeLayoutField f1,f2,f3,f4,f5,f6,f7,f8;
TypeLayoutField f9,f10,f11,f12,f13,f14,f15,f16;
#define make_typelayout(Tag, Value) \
(const Word *) (Tag), \
(const Word *) (Value)
#endif
/*
** Declaration for structs.
*/
#define MR_DECLARE_STRUCT(T) \
extern const struct T##_struct T
/*
** Typelayouts for builtins are often defined as X identical
** values, where X is the number of possible tag values.
*/
#if TAGBITS == 0
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value)
#elif TAGBITS == 1
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value)
#elif TAGBITS == 2
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value)
#elif TAGBITS == 3
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value)
#endif
#if !defined(make_typelayout_for_all_tags)
#error "make_typelayout_for_all_tags is not defined for this number of tags"
#endif
/*---------------------------------------------------------------------------*/
/*
** Tags in type_layout structures.
**
** These definitions are intended for use in handwritten
** C code.
**
** Some of the type-layout tags are shared.
*/
#define TYPELAYOUT_CONST_TAG 0
#define TYPELAYOUT_COMP_CONST_TAG 0
#define TYPELAYOUT_SIMPLE_TAG 1
#define TYPELAYOUT_COMPLICATED_TAG 2
#define TYPELAYOUT_EQUIV_TAG 3
#define TYPELAYOUT_NO_TAG 3
/*
** Values in type_layout structures,
** presently the values of CONST_TAG words.
**
** Also intended for use in handwritten C code.
**
** Note that TYPELAYOUT_UNASSIGNED_VALUE is not yet
** used for anything.
**
*/
#define TYPELAYOUT_UNASSIGNED_VALUE ((Integer) 0)
#define TYPELAYOUT_UNUSED_VALUE ((Integer) 1)
#define TYPELAYOUT_STRING_VALUE ((Integer) 2)
#define TYPELAYOUT_FLOAT_VALUE ((Integer) 3)
#define TYPELAYOUT_INT_VALUE ((Integer) 4)
#define TYPELAYOUT_CHARACTER_VALUE ((Integer) 5)
#define TYPELAYOUT_UNIV_VALUE ((Integer) 6)
#define TYPELAYOUT_PREDICATE_VALUE ((Integer) 7)
#define TYPELAYOUT_VOID_VALUE ((Integer) 8)
#define TYPELAYOUT_ARRAY_VALUE ((Integer) 9)
#define TYPELAYOUT_TYPEINFO_VALUE ((Integer) 10)
#define TYPELAYOUT_C_POINTER_VALUE ((Integer) 11)
/*
** Highest allowed type variable number
** (corresponds with argument number of type parameter).
*/
#define TYPELAYOUT_MAX_VARINT 1024
#define TYPEINFO_IS_VARIABLE(T) ( (Word) T <= TYPELAYOUT_MAX_VARINT )
/*
** This constant is also used for other information - for
** ctor infos a small integer is used for higher order types.
** Even integers represent preds, odd represent functions.
** The arity of the pred or function can be found by dividing by
** two (integer division).
*/
#define MR_BASE_TYPEINFO_HO_PRED \
((const Word *) &mercury_data___base_type_info_pred_0)
#define MR_BASE_TYPEINFO_HO_FUNC \
((const Word *) &mercury_data___base_type_info_func_0)
#define MR_BASE_TYPEINFO_IS_HO_PRED(T) \
(T == MR_BASE_TYPEINFO_HO_PRED)
#define MR_BASE_TYPEINFO_IS_HO_FUNC(T) \
(T == MR_BASE_TYPEINFO_HO_FUNC)
#define MR_BASE_TYPEINFO_IS_HO(T) \
(T == MR_BASE_TYPEINFO_HO_FUNC || T == MR_BASE_TYPEINFO_HO_PRED)
#define MR_TYPECTOR_IS_HIGHER_ORDER(T) \
( (Word) T <= TYPELAYOUT_MAX_VARINT )
#define MR_TYPECTOR_MAKE_PRED(Arity) \
( (Word) ((Integer) (Arity) * 2) )
#define MR_TYPECTOR_MAKE_FUNC(Arity) \
( (Word) ((Integer) (Arity) * 2 + 1) )
#define MR_TYPECTOR_GET_HOT_ARITY(T) \
((Integer) (T) / 2 )
#define MR_TYPECTOR_GET_HOT_NAME(T) \
((ConstString) ( ( ((Integer) (T)) % 2 ) ? "func" : "pred" ))
#define MR_TYPECTOR_GET_HOT_MODULE_NAME(T) \
((ConstString) "mercury_builtin")
#define MR_TYPECTOR_GET_HOT_BASE_TYPE_INFO(T) \
((Word) ( ( ((Integer) (T)) % 2 ) ? \
(const Word *) &mercury_data___base_type_info_func_0 : \
(const Word *) &mercury_data___base_type_info_pred_0 ))
/*
** Offsets into the type_layout structure for functors and arities.
**
** Constant and enumeration values start at 0, so the functor
** is at OFFSET + const/enum value.
**
** Functors for simple tags are at OFFSET + arity (the functor is
** stored after all the argument info.
**
*/
#define TYPELAYOUT_CONST_FUNCTOR_OFFSET 2
#define TYPELAYOUT_ENUM_FUNCTOR_OFFSET 2
#define TYPELAYOUT_SIMPLE_FUNCTOR_OFFSET 1
#define TYPELAYOUT_SIMPLE_ARITY_OFFSET 0
#define TYPELAYOUT_SIMPLE_ARGS_OFFSET 1
/*---------------------------------------------------------------------------*/
/*
** Offsets for dealing with `univ' types.
**
** `univ' is represented as a two word structure.
** The first word contains the address of a type_info for the type.
** The second word contains the data.
*/
#define UNIV_OFFSET_FOR_TYPEINFO 0
#define UNIV_OFFSET_FOR_DATA 1
/*---------------------------------------------------------------------------*/
/*
** Code for dealing with the static code addresses stored in
** base_type_infos.
*/
/*
** Static code addresses are available, unless using gcc non-local gotos,
** without assembler labels.
*/
#if (defined(USE_GCC_NONLOCAL_GOTOS) && !defined(USE_ASM_LABELS))
#undef MR_STATIC_CODE_ADDRESSES
#else
#define MR_STATIC_CODE_ADDRESSES
#endif
/*
** Definitions for initialization of base_type_infos. If
** MR_STATIC_CODE_ADDRESSES are not available, we need to initialize
** the special predicates in the base_type_infos.
*/
/*
** A fairly generic static code address initializer - at least for entry
** labels.
*/
#define MR_INIT_CODE_ADDR(Base, PredAddr, Offset) \
do { \
Declare_entry(PredAddr); \
((Word *) (Word) &Base)[Offset] = (Word) ENTRY(PredAddr);\
} while (0)
#define MR_SPECIAL_PRED_INIT(Base, TypeId, Offset, Pred) \
MR_INIT_CODE_ADDR(Base, mercury____##Pred##___##TypeId, Offset)
/*
** Macros are provided here to initialize base_type_infos, both for
** builtin types (such as in library/mercury_builtin.m) and user
** defined C types (like library/array.m). Also, the automatically
** generated code uses these initializers.
**
** Examples of use:
**
** MR_INIT_BUILTIN_BASE_TYPE_INFO(
** mercury_data__base_type_info_string_0, _string_);
**
** note we use _string_ to avoid the redefinition of string via #define
**
** MR_INIT_BASE_TYPE_INFO(
** mercury_data_group__base_type_info_group_1, group__group_1_0);
**
** MR_INIT_BASE_TYPE_INFO_WITH_PRED(
** mercury_date__base_type_info_void_0, mercury__unused_0_0);
**
** This will initialize a base_type_info with a single code address.
**
**
*/
#ifndef MR_STATIC_CODE_ADDRESSES
#define MR_MAYBE_STATIC_CODE(X) ((Integer) 0)
#define MR_STATIC_CODE_CONST
#ifdef USE_TYPE_TO_TERM
#define MR_INIT_BUILTIN_BASE_TYPE_INFO(B, T) \
do { \
MR_INIT_CODE_ADDR(B, mercury__builtin_unify##T##2_0, \
OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_index##T##2_0, \
OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_compare##T##3_0, \
OFFSET_FOR_COMPARE_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_type_to_term##T##2_0, \
OFFSET_FOR_TYPE_TO_TERM_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_term_to_type##T##2_0, \
OFFSET_FOR_TERM_TO_TYPE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO_WITH_PRED(B, P) \
do { \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_COMPARE_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_TYPE_TO_TERM_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_TERM_TO_TYPE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO(B, T) \
do { \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_UNIFY_PRED, Unify); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_INDEX_PRED, Index); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_COMPARE_PRED, Compare); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_TERM_TO_TYPE_PRED, Term_To_Type);\
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_TYPE_TO_TERM_PRED, Type_To_Term);\
} while (0)
#else /* not USE_TYPE_TO_TERM */
#define MR_INIT_BUILTIN_BASE_TYPE_INFO(B, T) \
do { \
MR_INIT_CODE_ADDR(B, mercury__builtin_unify##T##2_0, \
OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_index##T##2_0, \
OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_compare##T##3_0, \
OFFSET_FOR_COMPARE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO_WITH_PRED(B, P) \
do { \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_COMPARE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO(B, T) \
do { \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_UNIFY_PRED, Unify); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_INDEX_PRED, Index); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_COMPARE_PRED, Compare); \
} while (0)
#endif /* not USE_TYPE_TO_TERM */
#else /* MR_STATIC_CODE_ADDRESSES */
#define MR_MAYBE_STATIC_CODE(X) (X)
#define MR_STATIC_CODE_CONST const
#define MR_INIT_BUILTIN_BASE_TYPE_INFO(B, T) \
do { } while (0)
#define MR_INIT_BASE_TYPE_INFO_WITH_PRED(B, P) \
do { } while (0)
#define MR_INIT_BASE_TYPE_INFO(B, T) \
do { } while (0)
#endif /* MR_STATIC_CODE_ADDRESSES */
/*---------------------------------------------------------------------------*/
/*
** Macros and defintions for defining and dealing with
** base_type_functors.
*/
/*
** All type_functors have an indicator.
*/
#define MR_TYPEFUNCTORS_OFFSET_FOR_INDICATOR ((Integer) 0)
#define MR_TYPEFUNCTORS_INDICATOR(Functors) \
((Functors)[MR_TYPEFUNCTORS_OFFSET_FOR_INDICATOR])
/*
** Values that the indicator can take.
*/
#define MR_TYPEFUNCTORS_DU ((Integer) 0)
#define MR_TYPEFUNCTORS_ENUM ((Integer) 1)
#define MR_TYPEFUNCTORS_EQUIV ((Integer) 2)
#define MR_TYPEFUNCTORS_SPECIAL ((Integer) 3)
#define MR_TYPEFUNCTORS_NO_TAG ((Integer) 4)
#define MR_TYPEFUNCTORS_UNIV ((Integer) 5)
/*
** Macros to access the data in a discriminated union
** type_functors, the number of functors, and the simple_vector
** for functor number N (where N starts at 1).
*/
#define MR_TYPEFUNCTORS_DU_OFFSET_FOR_NUM_FUNCTORS ((Integer) 1)
#define MR_TYPEFUNCTORS_DU_OFFSET_FOR_FUNCTORS_VECTOR ((Integer) 2)
#define MR_TYPEFUNCTORS_DU_NUM_FUNCTORS(Functors) \
((Functors)[MR_TYPEFUNCTORS_DU_OFFSET_FOR_NUM_FUNCTORS])
#define MR_TYPEFUNCTORS_DU_FUNCTOR_N(Functor, N) \
((Word *) ((Functor)[ \
MR_TYPEFUNCTORS_DU_OFFSET_FOR_FUNCTORS_VECTOR + N]))
/*
** Macros to access the data in a enumeration type_functors, the
** number of functors, and the enumeration vector.
*/
#define MR_TYPEFUNCTORS_ENUM_OFFSET_FOR_FUNCTORS_VECTOR ((Integer) 1)
#define MR_TYPEFUNCTORS_ENUM_NUM_FUNCTORS(Functors) \
MR_TYPELAYOUT_ENUM_VECTOR_NUM_FUNCTORS( \
MR_TYPEFUNCTORS_ENUM_FUNCTORS((Functors)))
#define MR_TYPEFUNCTORS_ENUM_FUNCTORS(Functor) \
((Word *) ((Functor)[MR_TYPEFUNCTORS_ENUM_OFFSET_FOR_FUNCTORS_VECTOR]))
/*
** Macros to access the data in a no_tag type_functors, the
** simple_vector for the functor (there can only be one functor
** with no_tags).
*/
#define MR_TYPEFUNCTORS_NO_TAG_OFFSET_FOR_FUNCTORS_VECTOR ((Integer) 1)
#define MR_TYPEFUNCTORS_NO_TAG_FUNCTOR(Functors) \
((Word *) ((Functors) \
[MR_TYPEFUNCTORS_NO_TAG_OFFSET_FOR_FUNCTORS_VECTOR]))
/*
** Macros to access the data in an equivalence type_functors,
** the equivalent type of this type.
*/
#define MR_TYPEFUNCTORS_EQUIV_OFFSET_FOR_TYPE ((Integer) 1)
#define MR_TYPEFUNCTORS_EQUIV_TYPE(Functors) \
((Functors)[MR_TYPEFUNCTORS_EQUIV_OFFSET_FOR_TYPE])
/*---------------------------------------------------------------------------*/
/*
** Macros and defintions for defining and dealing with the vectors
** created by base_type_layouts (these are the same vectors referred to
** by base_type_functors)
** - the simple_vector, describing a single functor
** - the enum_vector, describing an enumeration
** - the no_tag_vector, describing a single functor
*/
/*
** Macros for dealing with enum vectors.
*/
typedef struct {
int enum_or_comp_const;
Word num_sharers;
ConstString functor1;
/* other functors follow, num_sharers of them.
** ConstString functor2;
** ...
*/
} MR_TypeLayout_EnumVector;
#define MR_TYPELAYOUT_ENUM_VECTOR_IS_ENUM(Vector) \
((MR_TypeLayout_EnumVector *) (Vector))->enum_or_comp_const
#define MR_TYPELAYOUT_ENUM_VECTOR_NUM_FUNCTORS(Vector) \
((MR_TypeLayout_EnumVector *) (Vector))->num_sharers
#define MR_TYPELAYOUT_ENUM_VECTOR_FUNCTOR_NAME(Vector, N) \
( (&((MR_TypeLayout_EnumVector *)(Vector))->functor1) [N] )
/*
** Macros for dealing with simple vectors.
*/
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARITY ((Integer) 0)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARGS ((Integer) 1)
/* Note, these offsets are from the end of the args */
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_NAME ((Integer) 1)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_TAG ((Integer) 2)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_ARITY(V) \
((V)[MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARITY])
#define MR_TYPELAYOUT_SIMPLE_VECTOR_ARGS(V) \
(V + MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARGS)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_FUNCTOR_NAME(V) \
((String) ((V)[MR_TYPELAYOUT_SIMPLE_VECTOR_ARITY(V) + \
MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_NAME]))
#define MR_TYPELAYOUT_SIMPLE_VECTOR_TAG(V) \
((Word) ((V)[MR_TYPELAYOUT_SIMPLE_VECTOR_ARITY(V) + \
MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_TAG]))
/*
** Macros for dealing with complicated vectors.
*/
typedef struct {
Word num_sharers;
Word simple_vector1;
/* other simple_vectors follow, num_sharers of them.
** Word simple_vector2;
** ...
*/
} MR_TypeLayout_ComplicatedVector;
#define MR_TYPELAYOUT_COMPLICATED_VECTOR_NUM_SHARERS(Vector) \
((MR_TypeLayout_ComplicatedVector *) (Vector))->num_sharers
#define MR_TYPELAYOUT_COMPLICATED_VECTOR_GET_SIMPLE_VECTOR(Vector, N) \
( (&((MR_TypeLayout_ComplicatedVector *)(Vector))->simple_vector1) [N] )
/*
** Macros for dealing with no_tag vectors
**
** (Note, we know the arity is 1).
*/
typedef struct {
int is_no_tag;
Word arg;
ConstString name;
} MR_TypeLayout_NoTagVector;
#define MR_TYPELAYOUT_NO_TAG_VECTOR_IS_NO_TAG(Vector) \
((MR_TypeLayout_NoTagVector *) (Vector))->is_no_tag
#define MR_TYPELAYOUT_NO_TAG_VECTOR_ARITY(Vector) \
(1)
#define MR_TYPELAYOUT_NO_TAG_VECTOR_ARGS(Vector) \
&(((MR_TypeLayout_NoTagVector *) (Vector))->arg)
#define MR_TYPELAYOUT_NO_TAG_VECTOR_FUNCTOR_NAME(Vector) \
((MR_TypeLayout_NoTagVector *) (Vector))->name
/*
** Macros for dealing with equivalent vectors
*/
typedef struct {
int is_no_tag; /* might be a no_tag */
Word equiv_type;
} MR_TypeLayout_EquivVector;
#define MR_TYPELAYOUT_EQUIV_OFFSET_FOR_TYPE ((Integer) 1)
#define MR_TYPELAYOUT_EQUIV_IS_EQUIV(Vector) \
(!((MR_TypeLayout_EquivVector *) (Vector))->is_no_tag)
#define MR_TYPELAYOUT_EQUIV_TYPE(Vector) \
((MR_TypeLayout_EquivVector *) (Vector))->equiv_type
/*---------------------------------------------------------------------------*/
/*
** Macros for retreiving things from type_infos and
** base_type_infos
*/
#define MR_TYPEINFO_GET_BASE_TYPEINFO(TypeInfo) \
((*TypeInfo) ? ((Word *) *TypeInfo) : TypeInfo)
#define MR_TYPEINFO_GET_HIGHER_ARITY(TypeInfo) \
((Integer) (Word *) (TypeInfo)[TYPEINFO_OFFSET_FOR_PRED_ARITY])
#define MR_BASE_TYPEINFO_GET_TYPEFUNCTORS(BaseTypeInfo) \
((Word *) (BaseTypeInfo)[OFFSET_FOR_BASE_TYPE_FUNCTORS])
#define MR_BASE_TYPEINFO_GET_TYPELAYOUT(BaseTypeInfo) \
((Word *) (BaseTypeInfo)[OFFSET_FOR_BASE_TYPE_LAYOUT])
#define MR_BASE_TYPEINFO_GET_TYPELAYOUT_ENTRY(BaseTypeInfo, Tag) \
(MR_BASE_TYPEINFO_GET_TYPELAYOUT(BaseTypeInfo)[(Tag)])
#define MR_BASE_TYPEINFO_GET_TYPE_ARITY(BaseTypeInfo) \
(((Word *) (BaseTypeInfo))[OFFSET_FOR_COUNT])
#define MR_BASE_TYPEINFO_GET_TYPE_NAME(BaseTypeInfo) \
(((String *) (BaseTypeInfo))[OFFSET_FOR_TYPE_NAME])
#define MR_BASE_TYPEINFO_GET_TYPE_MODULE_NAME(BaseTypeInfo) \
(((String *) (BaseTypeInfo))[OFFSET_FOR_TYPE_MODULE_NAME])
/*---------------------------------------------------------------------------*/
#if 0
/* XXX: We should use structs to represent the various
** data structures in the functors and layouts.
**
** To implement this:
** 1. The code that uses the data in the library and
** runtime should be modified to use the above access
** macros
** 2. Then we can simplify the ordering of the data
** structures (for example, put variable length fields
** last)
** 3. Then we can create structs for them.
**
** Some examples are below, (no guarantees of correctness).
**
** Note that enum_vectors have already been handled in this way.
*/
/*
** ** IMPORTANT: the layout in memory of the following
** struct must match the way that the Mercury compiler
** generates code for it.
*/
typedef struct {
Word arity;
Word arg1;
/* other arguments follow, there are arity of them,
** then followed by functor name, and functor tag.
** Word arg2;
** ...
** Word argarity;
** ConstString functorname;
** Word tag;
*/
} MR_TypeLayout_SimpleVector;
typedef struct {
Word arity;
Word arg_pseudo_type_infos[1]; /* variable-sized array */
/* actualy length is `arity', not 1 */
} MR_TypeLayout_part1;
typedef struct {
ConstString name;
Word arg_layouts[1]; /* variable-sized array */
/* actualy length is `arity', not 1 */
} MR_TypeLayout_part2;
typedef MR_TypeLayout_part1 MR_TypeLayout;
#endif
/*---------------------------------------------------------------------------*/
/*
** definitions for accessing the representation of the
** Mercury `array' type
*/
typedef struct {
Integer size;
Word elements[1]; /* really this is variable-length */
} MR_ArrayType;
#define MR_make_array(sz) ((MR_ArrayType *) make_many(Word, (sz) + 1))
/*---------------------------------------------------------------------------*/
#endif /* not TYPEINFO_H */

View File

@@ -12,7 +12,7 @@
#ifndef MERCURY_TYPES_H
#define MERCURY_TYPES_H
#include "conf.h"
#include "mercury_conf.h"
/*
** Note that we require sizeof(Word) == sizeof(Integer) == sizeof(Code*)

View File

@@ -1,4 +1,8 @@
/*
INIT mercury_sys_init_wrapper
ENDINIT
*/
/*
** Copyright (C) 1994-1997 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.
@@ -825,11 +829,19 @@ print_register_usage_counts(void)
} /* end print_register_usage_counts() */
#endif
BEGIN_MODULE(interpreter_module)
Define_extern_entry(do_interpreter);
Declare_label(global_success);
Declare_label(global_fail);
Declare_label(all_done);
BEGIN_MODULE(interpreter_module)
init_entry(do_interpreter);
init_label(global_success);
init_label(global_fail);
init_label(all_done);
BEGIN_CODE
do_interpreter:
Define_entry(do_interpreter);
push(MR_hp);
push(MR_succip);
push(MR_maxfr);
@@ -845,7 +857,7 @@ do_interpreter:
noprof_call(program_entry_point, LABEL(global_success));
global_success:
Define_label(global_success);
#ifndef SPEED
if (finaldebug) {
save_transient_registers();
@@ -860,7 +872,7 @@ global_success:
else
GOTO_LABEL(all_done);
global_fail:
Define_label(global_fail);
#ifndef SPEED
if (finaldebug) {
save_transient_registers();
@@ -871,7 +883,7 @@ global_fail:
}
#endif
all_done:
Define_label(all_done);
#ifdef PROFILE_TIME
prof_turn_off_time_profiling();
prof_output_addr_table();
@@ -895,7 +907,6 @@ all_done:
#ifndef USE_GCC_NONLOCAL_GOTOS
return 0;
#endif
END_MODULE
/*---------------------------------------------------------------------------*/
@@ -928,3 +939,7 @@ mercury_runtime_terminate(void)
}
/*---------------------------------------------------------------------------*/
void mercury_sys_init_wrapper(void); /* suppress gcc warning */
void mercury_sys_init_wrapper(void) {
interpreter_module();
}

88
runtime/mercury_wrapper.h Normal file
View File

@@ -0,0 +1,88 @@
/*
** Copyright (C) 1994-1997 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.
*/
/*
** wrapper.h - defines the interface to wrapper.mod.
** See wrapper.mod for documentation.
*/
#ifndef WRAPPER_H
#define WRAPPER_H
#include <stddef.h> /* for `size_t' */
#include "std.h" /* for `bool' */
/*
** 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);
/*
** 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.
*/
extern Code * program_entry_point; /* normally mercury__main_2_0; */
extern void (*MR_library_initializer)(void);
extern void (*MR_library_finalizer)(void);
extern void (*address_of_mercury_init_io)(void);
extern void (*address_of_init_modules)(void);
#ifdef CONSERVATIVE_GC
extern void (*address_of_init_gc)(void);
#endif
extern void do_init_modules(void);
extern const char * 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 heap_size;
extern size_t detstack_size;
extern size_t nondstack_size;
extern size_t solutions_heap_size;
extern size_t trail_size;
/* sizes of the red zones */
extern size_t heap_zone_size;
extern size_t detstack_zone_size;
extern size_t nondstack_zone_size;
extern size_t solutions_heap_zone_size;
extern size_t trail_zone_size;
/* size of the primary cache */
extern size_t pcache_size;
extern int r1val;
extern int r2val;
extern int r3val;
extern bool check_space;
extern int time_at_start;
extern int time_at_last_stat;
#endif /* not WRAPPER_H */

View File

@@ -4,67 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* misc.h - debugging messages, fatal_error(), and checked_malloc() */
#ifndef MISC_H
#define MISC_H
#include "mercury_types.h" /* for `Code *' */
#ifndef SPEED
extern void mkframe_msg(void);
extern void modframe_msg(void);
extern void succeed_msg(void);
extern void succeeddiscard_msg(void);
extern void fail_msg(void);
extern void redo_msg(void);
extern void call_msg(/* const */ Code *proc, /* const */ Code *succcont);
extern void tailcall_msg(/* const */ Code *proc);
extern void proceed_msg(void);
extern void cr1_msg(Word val0, const Word *addr);
extern void cr2_msg(Word val0, Word val1, const Word *addr);
extern void incr_hp_msg(Word val, const Word *addr);
extern void incr_sp_msg(Word val, const Word *addr);
extern void decr_sp_msg(Word val, const Word *addr);
extern void push_msg(Word val, const Word *addr);
extern void pop_msg(Word val, const Word *addr);
#endif
#if !defined(SPEED) || defined(DEBUG_GOTOS)
extern void goto_msg(/* const */ Code *addr);
extern void reg_msg(void);
#endif
#ifndef SPEED
extern void printint(Word n);
extern void printstring(const char *s);
extern void printheap(const Word *h);
extern void printdetstack(const Word *s);
extern void printnondstack(const Word *s);
extern void dumpframe(/* const */ Word *);
extern void dumpnondstack(void);
extern void printlist(Word p);
extern void printframe(const char *);
extern void printregs(const char *msg);
#endif
extern void printlabel(/* const */ Code *w);
#if __GNUC__
#define NO_RETURN __attribute__((noreturn))
#else
#define NO_RETURN
#endif
extern void fatal_error(const char *msg) NO_RETURN;
/* XXX checked_malloc() should be moved to memory.h or heap.h */
#include <stddef.h> /* for size_t */
void *checked_malloc(size_t n);
#endif /* not MISC_H */
#include "mercury_misc.h"

View File

@@ -4,75 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* overflow.h - definitions for overflow checks */
#ifndef OVERFLOW_H
#define OVERFLOW_H
#define IF(cond, val) ((cond) ? ((val), (void)0) : (void)0)
#ifdef SPEED
#define heap_overflow_check() ((void)0)
#define detstack_overflow_check() ((void)0)
#define detstack_underflow_check() ((void)0)
#define nondstack_overflow_check() ((void)0)
#define nondstack_underflow_check() ((void)0)
#else /* not SPEED */
#include "regs.h"
#include "misc.h" /* for fatal_error() */
#define heap_overflow_check() \
( \
IF (MR_hp >= heap_zone->top,( \
fatal_error("heap overflow") \
)), \
IF (MR_hp > heap_zone->max,( \
heap_zone->max = MR_hp \
)), \
(void)0 \
)
#define detstack_overflow_check() \
( \
IF (MR_sp >= detstack_zone->top,( \
fatal_error("stack overflow") \
)), \
IF (MR_sp > detstack_zone->max,( \
detstack_zone->max = MR_sp \
)), \
(void)0 \
)
#define detstack_underflow_check() \
( \
IF (MR_sp < detstack_zone->min,( \
fatal_error("stack underflow") \
)), \
(void)0 \
)
#define nondstack_overflow_check() \
( \
IF (MR_maxfr >= nondetstack_zone->top,( \
fatal_error("nondetstack overflow") \
)), \
IF (MR_maxfr > nondetstack_zone->max,( \
nondetstack_zone->max = MR_maxfr \
)), \
(void)0 \
)
#define nondstack_underflow_check() \
( \
IF (MR_maxfr < nondetstack_zone->min,( \
fatal_error("nondetstack underflow") \
)), \
(void)0 \
)
#endif /* not SPEED */
#endif /* not OVERFLOW_H */
#include "mercury_overflow.h"

View File

@@ -4,46 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* prof.h -- definitions for profiling */
#ifndef PROF_H
#define PROF_H
#include "mercury_types.h" /* for `Code *' */
/*
** this variable holds the address of the "current" procedure so that
** when a profiling interrupt occurs, the profiler knows where we are,
** so that it can credit the time to the appropriate procedure.
*/
extern Code * volatile prof_current_proc;
/*
** the following two macros are used to ensure that the profiler can
** use `prof_current_proc' to determine what procedure is currently
** being executed when a profiling interrupt occurs
*/
#ifdef PROFILE_TIME
#define set_prof_current_proc(target) (prof_current_proc = (target))
#define update_prof_current_proc(target) (prof_current_proc = (target))
#else
#define set_prof_current_proc(target) ((void)0)
#define update_prof_current_proc(target) ((void)0)
#endif
#ifdef PROFILE_CALLS
#define PROFILE(callee, caller) prof_call_profile((callee), (caller))
#else
#define PROFILE(callee, caller) ((void)0)
#endif
extern void prof_init_time_profile(void);
extern void prof_call_profile(Code *, Code *);
extern void prof_turn_off_time_profiling(void);
extern void prof_output_addr_pair_table(void);
extern void prof_output_addr_decls(const char *, const Code *);
extern void prof_output_addr_table(void);
#endif /* not PROF_H */
#include "mercury_prof.h"

View File

@@ -4,27 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** prof_mem.h - defines memory allocation functions used to hold
** the tables of profiling counts.
**
** Author: petdr
*/
#ifndef PROF_MEM_H
#define PROF_MEM_H
#include <stddef.h> /* for size_t */
/*
** prof_malloc() allocates memory in large chunks using newmem(),
** and then doles out portions of these chunks one at a time.
** We use prof_malloc() to reduce the chance of calling newmem()
** from a profiling interrupt that interrupted another call to newmem().
** Doing that is bad news, because newmem() is not re-entrant.
*/
void *prof_malloc(size_t);
#define prof_make(t) ((t *) prof_malloc(sizeof(t)))
#endif /* not PROF_MEM_H */
#include "mercury_prof_mem.h"

View File

@@ -4,109 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** regorder.h - defines the mapping from the Mercury abstract machine
** registers (r1, r2, ..., hp, sp, etc.) to the underlying intermediate-level
** abstract machine memory (mr0, mr1, ...).
**
** This file should be #included from "regs.h" and nowhere else.
** The reason this is separate from "regs.h" is so that it could,
** at least in theory, be generated automatically based on
** profiling feedback from the register usage counts for a particular
** application. However, currently we don't do that.
**
** If you change this file, you should also change the settings of
** NUM_REAL_R_REGS in ../configure.in.
*/
#ifndef REGORDER_H
#define REGORDER_H
#define r1 count_usage(R_RN(1), mr2)
#define r2 count_usage(R_RN(2), mr3)
#define r3 count_usage(R_RN(3), mr4)
#define r4 count_usage(R_RN(4), mr6)
#define r5 count_usage(R_RN(5), mr7)
#define r6 count_usage(R_RN(6), mr10)
#define r7 count_usage(R_RN(7), mr11)
#define r8 count_usage(R_RN(8), mr12)
#define r9 count_usage(R_RN(9), mr13)
#define r10 count_usage(R_RN(10), mr14)
#define r11 count_usage(R_RN(11), mr15)
#define r12 count_usage(R_RN(12), mr16)
#define r13 count_usage(R_RN(13), mr17)
#define r14 count_usage(R_RN(14), mr18)
#define r15 count_usage(R_RN(15), mr19)
#define r16 count_usage(R_RN(16), mr20)
#define r17 count_usage(R_RN(17), mr21)
#define r18 count_usage(R_RN(18), mr22)
#define r19 count_usage(R_RN(19), mr23)
#define r20 count_usage(R_RN(20), mr24)
#define r21 count_usage(R_RN(21), mr25)
#define r22 count_usage(R_RN(22), mr26)
#define r23 count_usage(R_RN(23), mr27)
#define r24 count_usage(R_RN(24), mr28)
#define r25 count_usage(R_RN(25), mr29)
#define r26 count_usage(R_RN(26), mr30)
#define r27 count_usage(R_RN(27), mr31)
#define r28 count_usage(R_RN(28), mr32)
#define r29 count_usage(R_RN(29), mr33)
#define r30 count_usage(R_RN(30), mr34)
#define r31 count_usage(R_RN(31), mr35)
#define r32 count_usage(R_RN(32), mr36)
#define MR_succip LVALUE_CAST(Code *, count_usage(MR_SI_RN, mr1))
#define succip MR_succip
#define MR_hp LVALUE_CAST(Word *, count_usage(MR_HP_RN, mr5))
#define hp MR_hp
#define MR_sp LVALUE_CAST(Word *, count_usage(MR_SP_RN, mr0))
#define sp MR_sp
#define MR_curfr LVALUE_CAST(Word *, count_usage(MR_CF_RN, mr8))
#define curfr MR_curfr
#define MR_maxfr LVALUE_CAST(Word *, count_usage(MR_MF_RN, mr9))
#define maxfr MR_maxfr
#define MR_sol_hp LVALUE_CAST(Word *, count_usage(MR_SOL_HP_RN, mr(37)))
#define MR_min_hp_rec LVALUE_CAST(Word *, count_usage(MR_MIN_HP_REC, mr(38)))
#define MR_min_sol_hp_rec LVALUE_CAST(Word *, \
count_usage(MR_MIN_HP_REC, mr39))
#define MR_trail_ptr count_usage(MR_TRAIL_PTR_RN, MR_trail_ptr_var)
#define MR_ticket_counter \
count_usage(MR_TICKET_COUNTER_RN, MR_ticket_counter_var)
#define VIRTUAL_REG_MAP_BODY { \
2, \
3, \
4, \
6, \
7, \
10, \
11, \
12, \
13, \
14, \
15, \
16, \
17, \
18, \
19, \
20, \
21, \
22, \
23, \
24, \
25, \
26, \
27, \
28, \
29, \
30, \
31, \
32, \
33, \
34, \
35, \
36, \
}
#endif /* not REGORDER_H */
#include "mercury_regorder.h"

View File

@@ -4,162 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
#ifndef REGS_H
#define REGS_H
#include "conf.h"
#include "mercury_types.h"
/*
** GNU C allows lvalue casts, so if we have gcc, use them.
** If we don't have gcc, then we can use *(type *)&lval,
** but that wouldn't work for gcc since lval might be a global
** register in which case we couldn't take it's address.
** Similarly for comma expressions and conditional expressions.
*/
#ifdef __GNUC__
#define LVALUE_CAST(type, lval) ((type)(lval))
#define LVALUE_SEQ(expr, lval) ((expr),(lval))
#define LVALUE_COND(expr, x, y) ((expr)?(x):(y))
#else
#define LVALUE_CAST(type, lval) (*(type*)&(lval))
#define LVALUE_SEQ(expr, lval) (*((expr),&(lval)))
#define LVALUE_COND(expr, x, y) (*((expr)?&(x):&(y)))
#endif
/*
** The registers of the Mercury virtual machine are built up using
** three levels of abstraction.
**
** The first level defines the first NUM_REAL_REGS register variables
** mr0, mr1, etc. as the physical machine registers, and defines an
** array fake_regs[n] of pseudo registers.
**
** The next level defines macros mr0 through mr36 and also mr(n) for
** n>36. The lower the number,
** the greater the probability that the storage referred to will be
** a real machine register, and not a simulated one. The number of
** real machine registers is given by the macro NUM_REAL_REGS.
**
** The final level maps the Mercury virtual machine registers
**
** succip, hp, sp, curfr, maxfr and
** r1, ..., r32, r(33), ..., r(MAX_VIRTUAL_REG)
**
** to the set mr0..mr36, mr(37), mr(38), ..., mr(MAX_FAKE_REG-1)
**
** Since the set of most frequently used Mercury virtual machine
** registers can be different for each program, we want to make
** this mapping as easy to change as possible. This is why the
** map is in a minimal header file, regorder.h.
*/
#if defined(USE_GCC_GLOBAL_REGISTERS)
#ifndef __GNUC__
#error "You must use gcc if you define USE_GCC_GLOBAL_REGISTERS."
#endif
#if defined(__mips__)
#include "machdeps/mips_regs.h"
#elif defined(__i386__)
#include "machdeps/i386_regs.h"
#elif defined(__sparc__)
#include "machdeps/sparc_regs.h"
#elif defined(__alpha__)
#include "machdeps/alpha_regs.h"
#elif defined(__hppa__)
#include "machdeps/pa_regs.h"
#elif defined(_POWER)
#include "machdeps/rs6000_regs.h"
#else
#error "USE_GCC_GLOBAL_REGISTERS not yet supported on this machine."
#endif
#else
#include "machdeps/no_regs.h"
#endif
/* The machdeps header defines mr0 .. mr36; now define mr(n) for n > 36 */
#define mr(n) LVALUE_SEQ(MR_assert((n) >= MAX_REAL_REG + NUM_SPECIAL_REG && \
(n) < MAX_FAKE_REG),\
fake_reg[n])
#ifdef MEASURE_REGISTER_USAGE
#define count_usage(num,reg) LVALUE_SEQ(num_uses[num]++, reg)
#else
#define count_usage(num,reg) (reg)
#endif
#include "regorder.h"
/* regorder.h defines r1 .. r32; now define r(n) for n > 32 */
#define r(n) mr((n) + NUM_SPECIAL_REG - 1)
/*
** the save_registers() macro copies the physical machine registers
** to their corresponding slots in the fake_reg array
*/
#define save_registers() save_regs_to_mem(fake_reg)
/*
** the restore_registers() macro sets the physical machine registers
** to the values in their corresponding slots in the fake_reg array
*/
#define restore_registers() restore_regs_from_mem(fake_reg)
/*
** the save_transient_registers() and restore_transient_registers()
** macros are similar to save_registers() and restore_registers()
** except that they only save/restore registers which can be
** affected by calling or returning from a C function (e.g.
** by sliding register windows on SPARCs).
*/
#define save_transient_registers() save_transient_regs_to_mem(fake_reg)
#define restore_transient_registers() restore_transient_regs_from_mem(fake_reg)
/* virtual_reg(n) accesses the underlying fake_reg for register n */
#define virtual_reg(n) \
LVALUE_COND((n) > MAX_REAL_REG, \
r(n), \
fake_reg[virtual_reg_map[(n) - 1]])
/*
** get_reg() and set_reg() provide a different way of addressing
** the registers; unlike virtual_reg(), you don't need to wrap them
** inside save_registers()/restore_regs() to copy the real regs to/from
** the fake_reg, so they may perhaps be more efficient if you are just
** getting or setting one or two registers?
** Currently they're buggy for n>32 and are not used except for debugging.
*/
extern Word get_reg(int);
extern Word set_reg(int, Word);
/*
** the following macros define a mapping from registers to indices into the
** num_uses array used for counting register usage
**
** any changes to these will also require changes to
** print_register_usage_counts() in wrapper.mod.
*/
#define MR_SI_RN 0
#define MR_R_RN(n) (n)
#define MR_ORD_RN MAX_REAL_REG
#define MR_HP_RN (MR_ORD_RN + 1)
#define MR_SP_RN (MR_ORD_RN + 2)
#define MR_CF_RN (MR_ORD_RN + 3)
#define MR_MF_RN (MR_ORD_RN + 4)
#define MR_TRAIL_PTR_RN (MR_ORD_RN + 5)
#define MR_TICKET_COUNTER_RN (MR_ORD_RN + 6)
#define MR_SOL_HP_RN (MR_ORD_RN + 7)
#define MR_MIN_HP_REC (MR_ORD_RN + 8)
#define MR_MIN_SOL_HP_REC (MR_ORD_RN + 9)
#define MAX_RN (MR_ORD_RN + 10)
#endif /* not REGS_H */
#include "mercury_regs.h"

View File

@@ -4,87 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* spinlock.h - defines spin locks (locks obtained by busy-waiting) */
#ifndef SPINLOCK_H
#define SPINLOCK_H
/*
** This part of the header file documents the abstract interface for a spinlock.
*/
#if 0 /* everything here is really implemented as macros */
/*
** You can assume that a SpinLock will fit into a Word,
** i.e. that sizeof(SpinLock) <= sizeof(Word).
** But you should not assume anything else.
*/
typedef ... SpinLock;
/*
** allocate_lock() returns a pointer to a new initialized lock,
** allocated in shared memory.
** deallocate_lock() deinitializes and deallocates a lock.
*/
extern SpinLock *allocate_lock(void);
extern void deallocate_lock(SpinLock *);
/*
** get_lock() and release_lock() are used to
** acquire and relinquish a lock.
*/
void get_lock(SpinLock *);
void release_lock(SpinLock *);
#endif /* 0 */
/*---------------------------------------------------------------------------*/
/*
** The following are implementation details.
** They're defined here in the header file so that they can be inlined,
** but code elsewhere should avoid depending on these details.
*/
#include "mercury_types.h" /* for `SpinLock' and `Word' */
#include <stddef.h> /* for `NULL' */
#include "conf.h" /* for `PARALLEL' */
#include "context.h" /* for `numprocs' */
void do_spinlock(SpinLock *s);
void do_spinunlock(SpinLock *s);
#ifdef PARALLEL
#define get_lock(addr) do { \
if (numprocs != 1) { \
do_spinlock(addr); \
} \
} while(0)
#define release_lock(addr) do { \
if (numprocs != 1) { \
do_spinunlock(addr); \
} \
} while(0)
#define allocate_lock() allocate_object(SpinLock)
#define deallocate_lock(lock) deallocate(lock)
#else /* not PARALLEL */
#define get_lock(addr) do { } while (0)
#define release_lock(addr) do { } while (0)
#define allocate_lock() NULL
#define deallocate_lock(lock) do { } while(0)
#endif /* not PARALLEL */
#endif /* not SPINLOCK_H */
#include "mercury_spinlock.h"

View File

@@ -4,172 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* stacks.h - definitions for manipulation the det and nondet stacks */
#ifndef STACKS_H
#define STACKS_H
#include "regs.h"
#include "mercury_types.h"
#include "overflow.h"
#include "debug.h"
#include "goto.h"
/* DEFINITIONS FOR MANIPULATING THE DET STACK */
#define detstackvar(n) (MR_sp[-n])
#define incr_sp_push_msg(n, msg) \
( \
debugincrsp(n, MR_sp), \
dump_push_msg(msg), \
MR_sp = MR_sp + (n), \
detstack_overflow_check(), \
(void)0 \
)
#define decr_sp_pop_msg(n) \
( \
debugdecrsp(n, MR_sp), \
dump_pop_msg(), \
MR_sp = MR_sp - (n), \
detstack_underflow_check(), \
(void)0 \
)
#define incr_sp(n) ( \
debugincrsp(n, MR_sp), \
MR_sp = MR_sp + (n), \
detstack_overflow_check(), \
(void)0 \
)
#define decr_sp(n) ( \
debugdecrsp(n, MR_sp), \
MR_sp = MR_sp - (n), \
detstack_underflow_check(), \
(void)0 \
)
#define push(w) ( \
*MR_sp = (Word) (w), \
debugpush(*sp, MR_sp), \
MR_sp = MR_sp + 1, \
detstack_overflow_check(), \
(void)0 \
)
#define pop() ( \
MR_sp = MR_sp - 1, \
debugpop(*MR_sp, MR_sp), \
detstack_underflow_check(), \
/* return */ *MR_sp \
)
/* DEFINITIONS FOR NONDET STACK FRAMES */
#define REDOIP (-0) /* in this proc, set up at clause entry */
#define PREVFR (-1) /* prev frame on stack, set up at call */
#define SUCCIP (-2) /* in caller proc, set up at call */
#define SUCCFR (-3) /* frame of caller proc, set up at call */
#ifdef SPEED
#define bt_prednm(fr) "unknown"
#define NONDET_FIXED_SIZE_0 4 /* units: words */
#else
#define PREDNM (-4) /* for debugging, set up at call */
#define bt_prednm(fr) LVALUE_CAST(const char *, ((Word *) fr)[PREDNM])
#define NONDET_FIXED_SIZE_0 5 /* units: words */
#endif
#define NONDET_FIXED_SIZE NONDET_FIXED_SIZE_0
#define SAVEVAL (-NONDET_FIXED_SIZE)
/* saved values start at this offset */
#define bt_redoip(fr) LVALUE_CAST(Code *, ((Word *) (fr))[REDOIP])
#define bt_prevfr(fr) LVALUE_CAST(Word *, ((Word *) (fr))[PREVFR])
#define bt_succip(fr) LVALUE_CAST(Code *, ((Word *) (fr))[SUCCIP])
#define bt_succfr(fr) LVALUE_CAST(Word *, ((Word *) (fr))[SUCCFR])
#define bt_var(fr,n) (((Word *) (fr))[SAVEVAL-(n)])
#define curprednm bt_prednm(MR_curfr)
#define curredoip bt_redoip(MR_curfr)
#define curprevfr bt_prevfr(MR_curfr)
#define cursuccip bt_succip(MR_curfr)
#define cursuccfr bt_succfr(MR_curfr)
#define framevar(n) bt_var(MR_curfr,n)
/* DEFINITIONS FOR MANIPULATING THE NONDET STACK */
#ifndef SPEED
#define mkframe_save_prednm(prednm) (curprednm = prednm)
#else
#define mkframe_save_prednm(prednm) /* nothing */
#endif
#define mkframe(prednm, numslots, redoip) \
do { \
reg Word *prevfr; \
reg Word *succfr; \
\
prevfr = MR_maxfr; \
succfr = MR_curfr; \
MR_maxfr += (NONDET_FIXED_SIZE + numslots);\
MR_curfr = MR_maxfr; \
curredoip = redoip; \
curprevfr = prevfr; \
cursuccip = MR_succip; \
cursuccfr = succfr; \
mkframe_save_prednm(prednm); \
debugmkframe(); \
nondstack_overflow_check(); \
} while (0)
#define modframe(redoip) \
do { \
curredoip = redoip; \
debugmodframe(); \
} while (0)
#define succeed() do { \
reg Word *childfr; \
\
debugsucceed(); \
childfr = MR_curfr; \
MR_curfr = cursuccfr; \
GOTO(bt_succip(childfr)); \
} while (0)
#define succeed_discard() \
do { \
reg Word *childfr; \
\
debugsucceeddiscard(); \
childfr = MR_curfr; \
MR_maxfr = curprevfr; \
MR_curfr = cursuccfr; \
GOTO(bt_succip(childfr)); \
} while (0)
#define fail() do { \
debugfail(); \
MR_maxfr = curprevfr; \
MR_curfr = MR_maxfr; \
nondstack_underflow_check(); \
GOTO(curredoip); \
} while (0)
#define redo() do { \
debugredo(); \
MR_curfr = MR_maxfr; \
GOTO(curredoip); \
} while (0)
#endif /* not STACKS_H */
#include "mercury_stacks.h"

View File

@@ -4,65 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** std.h - "standard" [sic] definitions for C:
** bool, TRUE, FALSE, min(), max(), streq(), etc.
*/
#ifndef STD_H
#define STD_H
#include <stdlib.h> /* for size_t */
#include <assert.h> /* for assert() */
#ifndef reg
#define reg register
#endif
#ifndef bool
#define bool char
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#define streq(s1, s2) (strcmp(s1, s2) == 0)
#define strdiff(s1, s2) (strcmp(s1, s2) != 0)
#define strtest(s1, s2) (strcmp(s1, s2))
#define strneq(s1, s2, n) (strncmp(s1, s2, n) == 0)
#define strndiff(s1, s2, n) (strncmp(s1, s2, n) != 0)
#define strntest(s1, s2, n) (strncmp(s1, s2, n))
#define ungetchar(c) ungetc(c, stdin)
/* XXX these should go in memory.h or heap.h */
#define make(t) ((t *) newmem(sizeof(t)))
#define make_many(t, n) ((t *) newmem((n) * sizeof(t)))
#define resize_many(t, p, n) ((t *) resizemem((p), (n) * sizeof(t)))
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*
** turn assertions off for speed
*/
#ifdef SPEED
#define MR_assert(ASSERTION) ((void)0)
#else
#define MR_assert(ASSERTION) assert(ASSERTION)
#endif
/* XXX these should go in memory.h or heap.h */
extern void *newmem(size_t);
extern void *resizemem(void *, size_t);
extern void oldmem(void *);
#endif /* not STD_H */
#include "mercury_std.h"

View File

@@ -4,39 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** table.h - defines the interface to the hash table module.
*/
#ifndef TABLE_H
#define TABLE_H
#include "std.h" /* for bool */
#include "dlist.h" /* for List */
typedef struct s_table {
int ta_size;
List **ta_store;
const void * (*ta_key)(const void *); /* applied to entries */
int (*ta_hash)(const void *); /* applied to keys */
bool (*ta_equal)(const void *, const void *);
/* applied to two keys */
} Table;
#define init_table(t) tab_init_table(&t)
#define lookup_table(t, k) tab_lookup_table(&t, (const void *) k)
#define insert_table(t, e) tab_insert_table(&t, (void *) e)
#define get_all_entries(t) tab_get_all_entries(&t)
#define str_to_int(val) tab_str_to_int(val)
#define tablekey(table) (*(table->ta_key))
#define tablehash(table) (*(table->ta_hash))
#define tableequal(table) (*(table->ta_equal))
extern void tab_init_table(Table *);
extern void * tab_lookup_table(const Table *, const void *);
extern bool tab_insert_table(const Table *, void *);
extern List *tab_get_all_entries(const Table *);
extern int tab_str_to_int(const char *);
#endif /* not TABLE_H */
#include "mercury_table.h"

View File

@@ -4,107 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** tags.h - defines macros for tagging and untagging words.
** Also defines macros for accessing the Mercury list type from C.
*/
#ifndef TAGS_H
#define TAGS_H
#include <limits.h> /* for `CHAR_BIT' */
#include "conf.h" /* for `LOW_TAG_BITS' */
#include "mercury_types.h" /* for `Word' */
/* DEFINITIONS FOR WORD LAYOUT */
#define WORDBITS (CHAR_BIT * sizeof(Word))
/* TAGBITS specifies the number of bits in each word that we can use for tags */
#ifndef TAGBITS
#ifdef HIGHTAGS
#error "HIGHTAGS defined but TAGBITS undefined"
#else
#define TAGBITS LOW_TAG_BITS
#endif
#endif
#if TAGBITS > 0 && defined(HIGHTAGS) && defined(CONSERVATIVE_GC)
#error "Conservative GC does not work with high tag bits"
#endif
#ifdef HIGHTAGS
#define mktag(t) ((Word)(t) << (WORDBITS - TAGBITS))
#define unmktag(w) ((Word)(w) >> (WORDBITS - TAGBITS))
#define tag(w) ((w) & ~(~(Word)0 >> TAGBITS))
#define mkbody(i) (i)
#define unmkbody(w) (w)
#define body(w, t) ((w) & (~(Word)0 >> TAGBITS))
#define strip_tag(w) ((w) & (~(Word)0 >> TAGBITS))
#else /* ! HIGHTAGS */
#define mktag(t) (t)
#define unmktag(w) (w)
#define tag(w) ((w) & ((1 << TAGBITS) - 1))
#define mkbody(i) ((i) << TAGBITS)
#define unmkbody(w) ((Word) (w) >> TAGBITS)
#define body(w, t) ((w) - (t))
#define strip_tag(w) ((w) & (~(Word)0 << TAGBITS))
#endif /* ! HIGHTAGS */
/*
** the result of mkword() is cast to (const Word *), not to (Word)
** because mkword() may be used in initializers for static constants
** and casts from pointers to integral types are not valid
** constant-expressions in ANSI C.
*/
#define mkword(t, p) ((const Word *)((const char *)(p) + (t)))
#define field(t, p, i) ((Word *) body((p), (t)))[i]
#define const_field(t, p, i) ((const Word *) body((p), (t)))[i]
/*
** the following list_* macros are used by handwritten C code
** that needs to access Mercury lists.
*/
#define bTAG_NIL 0
#define bTAG_CONS 1
#define bTAG_VAR 3 /* for Prolog-style variables */
/* ... but currently not used */
#define TAG_NIL mktag(bTAG_NIL)
#define TAG_CONS mktag(bTAG_CONS)
#define TAG_VAR mktag(bTAG_VAR)
#if TAGBITS > 0
#define list_is_empty(list) (tag(list) == TAG_NIL)
#define list_head(list) field(TAG_CONS, (list), 0)
#define list_tail(list) field(TAG_CONS, (list), 1)
#define list_empty() ((Word) mkword(TAG_NIL, mkbody(0)))
#define list_cons(head,tail) \
((Word) mkword(TAG_CONS, create2((head),(tail))))
#else
#define list_is_empty(list) (field(mktag(0), (list), 0) == bTAG_NIL)
#define list_head(list) field(mktag(0), (list), 1)
#define list_tail(list) field(mktag(0), (list), 2)
#define list_empty() ((Word) mkword(mktag(0), create1(bTAG_NIL)))
#define list_cons(head,tail) \
((Word) mkword(mktag(0), create3(bTAG_CONS, (head), (tail))))
#endif
/* for Prolog-style variables... currently not used */
#define deref(pt) do { \
while (tag(pt) == TAG_VAR) \
(pt) = * (Word *) \
body((pt), TAG_VAR); \
} while(0)
#endif /* not TAGS_H */
#include "mercury_tags.h"

View File

@@ -4,44 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** timing.h - interface to timing routines.
** Defines `MR_CLOCK_TICKS_PER_SECOND'
** and `MR_get_user_cpu_miliseconds()'.
*/
#ifndef TIMING_H
#define TIMING_H
#include "conf.h"
#ifdef HAVE_SYS_PARAM
#include <sys/param.h> /* for HZ */
#endif
#include <unistd.h> /* for sysconf() and _SC_CLK_TCK */
#include <limits.h> /* CLK_TCK defined here, on some systems */
/*
** `HZ' is the number of clock ticks per second.
** It is used when converting a clock_t value to a time in seconds.
** It may be defined by <sys/time.h>, but if it is not defined there,
** we may be able to use `sysconf(_SC_CLK_TCK)' or CLK_TCK instead.
*/
#ifdef HZ
#define MR_CLOCK_TICKS_PER_SECOND HZ
#elif defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
#define MR_CLOCK_TICKS_PER_SECOND ((int) sysconf(_SC_CLK_TCK))
#elif defined(CLK_TCK)
#define MR_CLOCK_TICKS_PER_SECOND CLK_TCK
#else
/* just leave it undefined */
#endif
/*
** MR_get_user_cpu_miliseconds() returns the CPU time consumed by the
** process, in miliseconds, from an arbitrary initial time.
*/
int MR_get_user_cpu_miliseconds(void);
#endif /* TIMING_H */
#include "mercury_timing.h"

View File

@@ -4,785 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** type_info.h -
** Definitions for accessing the type_infos, type_layouts, and
** type_functors tables generated by the Mercury compiler.
** Also contains definitions for accessing the Mercury `univ' type
** and the Mercury `array' type.
*/
#ifndef TYPE_INFO_H
#define TYPE_INFO_H
#include "mercury_types.h" /* for `Word' */
/*---------------------------------------------------------------------------*/
/*
** Decide which type_info representation we will use.
**
** At present, only SHARED_ONE_OR_TWO_CELL_TYPE_INFO is available.
**
*/
#define SHARED_ONE_OR_TWO_CELL_TYPE_INFO
/*---------------------------------------------------------------------------*/
/*
** Define offsets of fields in the base_type_info or type_info structure.
** See polymorphism.m for explanation of these offsets and how the
** type_info and base_type_info structures are laid out.
**
** ANY CHANGES HERE MUST BE MATCHED BY CORRESPONDING CHANGES
** TO THE DOCUMENTATION IN compiler/polymorphism.m.
**
** The one_or_two_cell type_info representation
** *depends* on OFFSET_FOR_COUNT being 0.
*/
#define OFFSET_FOR_COUNT 0
#define OFFSET_FOR_UNIFY_PRED 1
#define OFFSET_FOR_INDEX_PRED 2
#define OFFSET_FOR_COMPARE_PRED 3
#define OFFSET_FOR_BASE_TYPE_LAYOUT 4
#define OFFSET_FOR_BASE_TYPE_FUNCTORS 5
#define OFFSET_FOR_TYPE_MODULE_NAME 6
#define OFFSET_FOR_TYPE_NAME 7
/*
** Define offsets of fields in the type_info structure.
*/
#define OFFSET_FOR_ARG_TYPE_INFOS 1
/*
** Where the predicate arity and args are stored in the type_info.
** For one-or-two-cell, they are stored in the type_info (*not* the
** base_type_info).
** This is brought about by higher-order predicates all using the
** same base_type_info - pred/0.
** For one-cell, the arity is at the same offset as the count.
*/
#define TYPEINFO_OFFSET_FOR_PRED_ARITY 1
#define TYPEINFO_OFFSET_FOR_PRED_ARGS 2
/*---------------------------------------------------------------------------*/
/*
** Definitions for handwritten code, mostly for mercury_compare_typeinfo.
*/
#define COMPARE_EQUAL 0
#define COMPARE_LESS 1
#define COMPARE_GREATER 2
#ifdef COMPACT_ARGS
#define mercury__unify__typeinfo r1
#define mercury__unify__x r2
#define mercury__unify__y r3
#define mercury__unify__offset 0
#define mercury__compare__typeinfo r1
#define mercury__compare__x r2
#define mercury__compare__y r3
#define mercury__compare__offset 0
#define mercury__term_to_type__typeinfo r1
#define mercury__term_to_type__term r2
#define mercury__term_to_type__x r4
#define mercury__term_to_type__offset 1
#define unify_input1 r1
#define unify_input2 r2
#define unify_output r1
#define compare_input1 r1
#define compare_input2 r2
#define compare_output r1
#define index_input r1
#define index_output r1
#else
#define mercury__unify__typeinfo r2
#define mercury__unify__x r3
#define mercury__unify__y r4
#define mercury__unify__offset 1
#define mercury__compare__typeinfo r1
#define mercury__compare__x r3
#define mercury__compare__y r4
#define mercury__compare__offset 1
#define mercury__term_to_type__typeinfo r2
#define mercury__term_to_type__term r3
#define mercury__term_to_type__x r4
#define mercury__term_to_type__offset 1
#define unify_input1 r2
#define unify_input2 r3
#define unify_output r1
#define compare_input1 r2
#define compare_input2 r3
#define compare_output r1
#define index_input r1
#define index_output r2
#endif
/*---------------------------------------------------------------------------*/
/*
** Definitions and macros for base_type_layout definition.
**
** See compiler/base_type_layout.m for more information.
**
** If we don't have enough tags, we have to encode layouts
** less densely. The make_typelayout macro does this, and
** is intended for handwritten code. Compiler generated
** code can (and does) just create two rvals instead of one.
**
*/
/*
** Conditionally define USE_TYPE_LAYOUT.
**
** All code using type_layout structures should check to see if
** USE_TYPE_LAYOUT is defined, and give a fatal error otherwise.
** For USE_TYPE_LAYOUT to be defined, we need to be using
** shared one-or-two cell type_infos (since the type_layouts refer
** to base_type_layouts). USE_TYPE_LAYOUT can be explicitly turned
** off with NO_TYPE_LAYOUT.
**
*/
#if defined(SHARED_ONE_OR_TWO_CELL_TYPE_INFO) && !defined(NO_TYPE_LAYOUT)
#define USE_TYPE_LAYOUT
#else
#undef USE_TYPE_LAYOUT
#endif
/*
** Code intended for defining type_layouts for handwritten code.
**
** See library/io.m or library/mercury_builtin.m for details.
*/
#if TAGBITS >= 2
typedef const Word *TypeLayoutField;
#define TYPE_LAYOUT_FIELDS \
TypeLayoutField f1,f2,f3,f4,f5,f6,f7,f8;
#define make_typelayout(Tag, Value) \
mkword(mktag(Tag), (Value))
#else
typedef const Word *TypeLayoutField;
#define TYPE_LAYOUT_FIELDS \
TypeLayoutField f1,f2,f3,f4,f5,f6,f7,f8;
TypeLayoutField f9,f10,f11,f12,f13,f14,f15,f16;
#define make_typelayout(Tag, Value) \
(const Word *) (Tag), \
(const Word *) (Value)
#endif
/*
** Declaration for structs.
*/
#define MR_DECLARE_STRUCT(T) \
extern const struct T##_struct T
/*
** Typelayouts for builtins are often defined as X identical
** values, where X is the number of possible tag values.
*/
#if TAGBITS == 0
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value)
#elif TAGBITS == 1
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value)
#elif TAGBITS == 2
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value)
#elif TAGBITS == 3
#define make_typelayout_for_all_tags(Tag, Value) \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value), \
make_typelayout(Tag, Value)
#endif
#if !defined(make_typelayout_for_all_tags)
#error "make_typelayout_for_all_tags is not defined for this number of tags"
#endif
/*---------------------------------------------------------------------------*/
/*
** Tags in type_layout structures.
**
** These definitions are intended for use in handwritten
** C code.
**
** Some of the type-layout tags are shared.
*/
#define TYPELAYOUT_CONST_TAG 0
#define TYPELAYOUT_COMP_CONST_TAG 0
#define TYPELAYOUT_SIMPLE_TAG 1
#define TYPELAYOUT_COMPLICATED_TAG 2
#define TYPELAYOUT_EQUIV_TAG 3
#define TYPELAYOUT_NO_TAG 3
/*
** Values in type_layout structures,
** presently the values of CONST_TAG words.
**
** Also intended for use in handwritten C code.
**
** Note that TYPELAYOUT_UNASSIGNED_VALUE is not yet
** used for anything.
**
*/
#define TYPELAYOUT_UNASSIGNED_VALUE ((Integer) 0)
#define TYPELAYOUT_UNUSED_VALUE ((Integer) 1)
#define TYPELAYOUT_STRING_VALUE ((Integer) 2)
#define TYPELAYOUT_FLOAT_VALUE ((Integer) 3)
#define TYPELAYOUT_INT_VALUE ((Integer) 4)
#define TYPELAYOUT_CHARACTER_VALUE ((Integer) 5)
#define TYPELAYOUT_UNIV_VALUE ((Integer) 6)
#define TYPELAYOUT_PREDICATE_VALUE ((Integer) 7)
#define TYPELAYOUT_VOID_VALUE ((Integer) 8)
#define TYPELAYOUT_ARRAY_VALUE ((Integer) 9)
#define TYPELAYOUT_TYPEINFO_VALUE ((Integer) 10)
#define TYPELAYOUT_C_POINTER_VALUE ((Integer) 11)
/*
** Highest allowed type variable number
** (corresponds with argument number of type parameter).
*/
#define TYPELAYOUT_MAX_VARINT 1024
#define TYPEINFO_IS_VARIABLE(T) ( (Word) T <= TYPELAYOUT_MAX_VARINT )
/*
** This constant is also used for other information - for
** ctor infos a small integer is used for higher order types.
** Even integers represent preds, odd represent functions.
** The arity of the pred or function can be found by dividing by
** two (integer division).
*/
#define MR_BASE_TYPEINFO_HO_PRED \
((const Word *) &mercury_data___base_type_info_pred_0)
#define MR_BASE_TYPEINFO_HO_FUNC \
((const Word *) &mercury_data___base_type_info_func_0)
#define MR_BASE_TYPEINFO_IS_HO_PRED(T) \
(T == MR_BASE_TYPEINFO_HO_PRED)
#define MR_BASE_TYPEINFO_IS_HO_FUNC(T) \
(T == MR_BASE_TYPEINFO_HO_FUNC)
#define MR_BASE_TYPEINFO_IS_HO(T) \
(T == MR_BASE_TYPEINFO_HO_FUNC || T == MR_BASE_TYPEINFO_HO_PRED)
#define MR_TYPECTOR_IS_HIGHER_ORDER(T) \
( (Word) T <= TYPELAYOUT_MAX_VARINT )
#define MR_TYPECTOR_MAKE_PRED(Arity) \
( (Word) ((Integer) (Arity) * 2) )
#define MR_TYPECTOR_MAKE_FUNC(Arity) \
( (Word) ((Integer) (Arity) * 2 + 1) )
#define MR_TYPECTOR_GET_HOT_ARITY(T) \
((Integer) (T) / 2 )
#define MR_TYPECTOR_GET_HOT_NAME(T) \
((ConstString) ( ( ((Integer) (T)) % 2 ) ? "func" : "pred" ))
#define MR_TYPECTOR_GET_HOT_MODULE_NAME(T) \
((ConstString) "mercury_builtin")
#define MR_TYPECTOR_GET_HOT_BASE_TYPE_INFO(T) \
((Word) ( ( ((Integer) (T)) % 2 ) ? \
(const Word *) &mercury_data___base_type_info_func_0 : \
(const Word *) &mercury_data___base_type_info_pred_0 ))
/*
** Offsets into the type_layout structure for functors and arities.
**
** Constant and enumeration values start at 0, so the functor
** is at OFFSET + const/enum value.
**
** Functors for simple tags are at OFFSET + arity (the functor is
** stored after all the argument info.
**
*/
#define TYPELAYOUT_CONST_FUNCTOR_OFFSET 2
#define TYPELAYOUT_ENUM_FUNCTOR_OFFSET 2
#define TYPELAYOUT_SIMPLE_FUNCTOR_OFFSET 1
#define TYPELAYOUT_SIMPLE_ARITY_OFFSET 0
#define TYPELAYOUT_SIMPLE_ARGS_OFFSET 1
/*---------------------------------------------------------------------------*/
/*
** Offsets for dealing with `univ' types.
**
** `univ' is represented as a two word structure.
** The first word contains the address of a type_info for the type.
** The second word contains the data.
*/
#define UNIV_OFFSET_FOR_TYPEINFO 0
#define UNIV_OFFSET_FOR_DATA 1
/*---------------------------------------------------------------------------*/
/*
** Code for dealing with the static code addresses stored in
** base_type_infos.
*/
/*
** Static code addresses are available, unless using gcc non-local gotos,
** without assembler labels.
*/
#if (defined(USE_GCC_NONLOCAL_GOTOS) && !defined(USE_ASM_LABELS))
#undef MR_STATIC_CODE_ADDRESSES
#else
#define MR_STATIC_CODE_ADDRESSES
#endif
/*
** Definitions for initialization of base_type_infos. If
** MR_STATIC_CODE_ADDRESSES are not available, we need to initialize
** the special predicates in the base_type_infos.
*/
/*
** A fairly generic static code address initializer - at least for entry
** labels.
*/
#define MR_INIT_CODE_ADDR(Base, PredAddr, Offset) \
do { \
Declare_entry(PredAddr); \
((Word *) (Word) &Base)[Offset] = (Word) ENTRY(PredAddr);\
} while (0)
#define MR_SPECIAL_PRED_INIT(Base, TypeId, Offset, Pred) \
MR_INIT_CODE_ADDR(Base, mercury____##Pred##___##TypeId, Offset)
/*
** Macros are provided here to initialize base_type_infos, both for
** builtin types (such as in library/mercury_builtin.m) and user
** defined C types (like library/array.m). Also, the automatically
** generated code uses these initializers.
**
** Examples of use:
**
** MR_INIT_BUILTIN_BASE_TYPE_INFO(
** mercury_data__base_type_info_string_0, _string_);
**
** note we use _string_ to avoid the redefinition of string via #define
**
** MR_INIT_BASE_TYPE_INFO(
** mercury_data_group__base_type_info_group_1, group__group_1_0);
**
** MR_INIT_BASE_TYPE_INFO_WITH_PRED(
** mercury_date__base_type_info_void_0, mercury__unused_0_0);
**
** This will initialize a base_type_info with a single code address.
**
**
*/
#ifndef MR_STATIC_CODE_ADDRESSES
#define MR_MAYBE_STATIC_CODE(X) ((Integer) 0)
#define MR_STATIC_CODE_CONST
#ifdef USE_TYPE_TO_TERM
#define MR_INIT_BUILTIN_BASE_TYPE_INFO(B, T) \
do { \
MR_INIT_CODE_ADDR(B, mercury__builtin_unify##T##2_0, \
OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_index##T##2_0, \
OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_compare##T##3_0, \
OFFSET_FOR_COMPARE_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_type_to_term##T##2_0, \
OFFSET_FOR_TYPE_TO_TERM_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_term_to_type##T##2_0, \
OFFSET_FOR_TERM_TO_TYPE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO_WITH_PRED(B, P) \
do { \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_COMPARE_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_TYPE_TO_TERM_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_TERM_TO_TYPE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO(B, T) \
do { \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_UNIFY_PRED, Unify); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_INDEX_PRED, Index); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_COMPARE_PRED, Compare); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_TERM_TO_TYPE_PRED, Term_To_Type);\
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_TYPE_TO_TERM_PRED, Type_To_Term);\
} while (0)
#else /* not USE_TYPE_TO_TERM */
#define MR_INIT_BUILTIN_BASE_TYPE_INFO(B, T) \
do { \
MR_INIT_CODE_ADDR(B, mercury__builtin_unify##T##2_0, \
OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_index##T##2_0, \
OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, mercury__builtin_compare##T##3_0, \
OFFSET_FOR_COMPARE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO_WITH_PRED(B, P) \
do { \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_UNIFY_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_INDEX_PRED); \
MR_INIT_CODE_ADDR(B, P, OFFSET_FOR_COMPARE_PRED); \
} while (0)
#define MR_INIT_BASE_TYPE_INFO(B, T) \
do { \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_UNIFY_PRED, Unify); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_INDEX_PRED, Index); \
MR_SPECIAL_PRED_INIT(B, T, OFFSET_FOR_COMPARE_PRED, Compare); \
} while (0)
#endif /* not USE_TYPE_TO_TERM */
#else /* MR_STATIC_CODE_ADDRESSES */
#define MR_MAYBE_STATIC_CODE(X) (X)
#define MR_STATIC_CODE_CONST const
#define MR_INIT_BUILTIN_BASE_TYPE_INFO(B, T) \
do { } while (0)
#define MR_INIT_BASE_TYPE_INFO_WITH_PRED(B, P) \
do { } while (0)
#define MR_INIT_BASE_TYPE_INFO(B, T) \
do { } while (0)
#endif /* MR_STATIC_CODE_ADDRESSES */
/*---------------------------------------------------------------------------*/
/*
** Macros and defintions for defining and dealing with
** base_type_functors.
*/
/*
** All type_functors have an indicator.
*/
#define MR_TYPEFUNCTORS_OFFSET_FOR_INDICATOR ((Integer) 0)
#define MR_TYPEFUNCTORS_INDICATOR(Functors) \
((Functors)[MR_TYPEFUNCTORS_OFFSET_FOR_INDICATOR])
/*
** Values that the indicator can take.
*/
#define MR_TYPEFUNCTORS_DU ((Integer) 0)
#define MR_TYPEFUNCTORS_ENUM ((Integer) 1)
#define MR_TYPEFUNCTORS_EQUIV ((Integer) 2)
#define MR_TYPEFUNCTORS_SPECIAL ((Integer) 3)
#define MR_TYPEFUNCTORS_NO_TAG ((Integer) 4)
#define MR_TYPEFUNCTORS_UNIV ((Integer) 5)
/*
** Macros to access the data in a discriminated union
** type_functors, the number of functors, and the simple_vector
** for functor number N (where N starts at 1).
*/
#define MR_TYPEFUNCTORS_DU_OFFSET_FOR_NUM_FUNCTORS ((Integer) 1)
#define MR_TYPEFUNCTORS_DU_OFFSET_FOR_FUNCTORS_VECTOR ((Integer) 2)
#define MR_TYPEFUNCTORS_DU_NUM_FUNCTORS(Functors) \
((Functors)[MR_TYPEFUNCTORS_DU_OFFSET_FOR_NUM_FUNCTORS])
#define MR_TYPEFUNCTORS_DU_FUNCTOR_N(Functor, N) \
((Word *) ((Functor)[ \
MR_TYPEFUNCTORS_DU_OFFSET_FOR_FUNCTORS_VECTOR + N]))
/*
** Macros to access the data in a enumeration type_functors, the
** number of functors, and the enumeration vector.
*/
#define MR_TYPEFUNCTORS_ENUM_OFFSET_FOR_FUNCTORS_VECTOR ((Integer) 1)
#define MR_TYPEFUNCTORS_ENUM_NUM_FUNCTORS(Functors) \
MR_TYPELAYOUT_ENUM_VECTOR_NUM_FUNCTORS( \
MR_TYPEFUNCTORS_ENUM_FUNCTORS((Functors)))
#define MR_TYPEFUNCTORS_ENUM_FUNCTORS(Functor) \
((Word *) ((Functor)[MR_TYPEFUNCTORS_ENUM_OFFSET_FOR_FUNCTORS_VECTOR]))
/*
** Macros to access the data in a no_tag type_functors, the
** simple_vector for the functor (there can only be one functor
** with no_tags).
*/
#define MR_TYPEFUNCTORS_NO_TAG_OFFSET_FOR_FUNCTORS_VECTOR ((Integer) 1)
#define MR_TYPEFUNCTORS_NO_TAG_FUNCTOR(Functors) \
((Word *) ((Functors) \
[MR_TYPEFUNCTORS_NO_TAG_OFFSET_FOR_FUNCTORS_VECTOR]))
/*
** Macros to access the data in an equivalence type_functors,
** the equivalent type of this type.
*/
#define MR_TYPEFUNCTORS_EQUIV_OFFSET_FOR_TYPE ((Integer) 1)
#define MR_TYPEFUNCTORS_EQUIV_TYPE(Functors) \
((Functors)[MR_TYPEFUNCTORS_EQUIV_OFFSET_FOR_TYPE])
/*---------------------------------------------------------------------------*/
/*
** Macros and defintions for defining and dealing with the vectors
** created by base_type_layouts (these are the same vectors referred to
** by base_type_functors)
** - the simple_vector, describing a single functor
** - the enum_vector, describing an enumeration
** - the no_tag_vector, describing a single functor
*/
/*
** Macros for dealing with enum vectors.
*/
typedef struct {
int enum_or_comp_const;
Word num_sharers;
ConstString functor1;
/* other functors follow, num_sharers of them.
** ConstString functor2;
** ...
*/
} MR_TypeLayout_EnumVector;
#define MR_TYPELAYOUT_ENUM_VECTOR_IS_ENUM(Vector) \
((MR_TypeLayout_EnumVector *) (Vector))->enum_or_comp_const
#define MR_TYPELAYOUT_ENUM_VECTOR_NUM_FUNCTORS(Vector) \
((MR_TypeLayout_EnumVector *) (Vector))->num_sharers
#define MR_TYPELAYOUT_ENUM_VECTOR_FUNCTOR_NAME(Vector, N) \
( (&((MR_TypeLayout_EnumVector *)(Vector))->functor1) [N] )
/*
** Macros for dealing with simple vectors.
*/
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARITY ((Integer) 0)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARGS ((Integer) 1)
/* Note, these offsets are from the end of the args */
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_NAME ((Integer) 1)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_TAG ((Integer) 2)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_ARITY(V) \
((V)[MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARITY])
#define MR_TYPELAYOUT_SIMPLE_VECTOR_ARGS(V) \
(V + MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_ARGS)
#define MR_TYPELAYOUT_SIMPLE_VECTOR_FUNCTOR_NAME(V) \
((String) ((V)[MR_TYPELAYOUT_SIMPLE_VECTOR_ARITY(V) + \
MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_NAME]))
#define MR_TYPELAYOUT_SIMPLE_VECTOR_TAG(V) \
((Word) ((V)[MR_TYPELAYOUT_SIMPLE_VECTOR_ARITY(V) + \
MR_TYPELAYOUT_SIMPLE_VECTOR_OFFSET_FOR_FUNCTOR_TAG]))
/*
** Macros for dealing with complicated vectors.
*/
typedef struct {
Word num_sharers;
Word simple_vector1;
/* other simple_vectors follow, num_sharers of them.
** Word simple_vector2;
** ...
*/
} MR_TypeLayout_ComplicatedVector;
#define MR_TYPELAYOUT_COMPLICATED_VECTOR_NUM_SHARERS(Vector) \
((MR_TypeLayout_ComplicatedVector *) (Vector))->num_sharers
#define MR_TYPELAYOUT_COMPLICATED_VECTOR_GET_SIMPLE_VECTOR(Vector, N) \
( (&((MR_TypeLayout_ComplicatedVector *)(Vector))->simple_vector1) [N] )
/*
** Macros for dealing with no_tag vectors
**
** (Note, we know the arity is 1).
*/
typedef struct {
int is_no_tag;
Word arg;
ConstString name;
} MR_TypeLayout_NoTagVector;
#define MR_TYPELAYOUT_NO_TAG_VECTOR_IS_NO_TAG(Vector) \
((MR_TypeLayout_NoTagVector *) (Vector))->is_no_tag
#define MR_TYPELAYOUT_NO_TAG_VECTOR_ARITY(Vector) \
(1)
#define MR_TYPELAYOUT_NO_TAG_VECTOR_ARGS(Vector) \
&(((MR_TypeLayout_NoTagVector *) (Vector))->arg)
#define MR_TYPELAYOUT_NO_TAG_VECTOR_FUNCTOR_NAME(Vector) \
((MR_TypeLayout_NoTagVector *) (Vector))->name
/*
** Macros for dealing with equivalent vectors
*/
typedef struct {
int is_no_tag; /* might be a no_tag */
Word equiv_type;
} MR_TypeLayout_EquivVector;
#define MR_TYPELAYOUT_EQUIV_OFFSET_FOR_TYPE ((Integer) 1)
#define MR_TYPELAYOUT_EQUIV_IS_EQUIV(Vector) \
(!((MR_TypeLayout_EquivVector *) (Vector))->is_no_tag)
#define MR_TYPELAYOUT_EQUIV_TYPE(Vector) \
((MR_TypeLayout_EquivVector *) (Vector))->equiv_type
/*---------------------------------------------------------------------------*/
/*
** Macros for retreiving things from type_infos and
** base_type_infos
*/
#define MR_TYPEINFO_GET_BASE_TYPEINFO(TypeInfo) \
((*TypeInfo) ? ((Word *) *TypeInfo) : TypeInfo)
#define MR_TYPEINFO_GET_HIGHER_ARITY(TypeInfo) \
((Integer) (Word *) (TypeInfo)[TYPEINFO_OFFSET_FOR_PRED_ARITY])
#define MR_BASE_TYPEINFO_GET_TYPEFUNCTORS(BaseTypeInfo) \
((Word *) (BaseTypeInfo)[OFFSET_FOR_BASE_TYPE_FUNCTORS])
#define MR_BASE_TYPEINFO_GET_TYPELAYOUT(BaseTypeInfo) \
((Word *) (BaseTypeInfo)[OFFSET_FOR_BASE_TYPE_LAYOUT])
#define MR_BASE_TYPEINFO_GET_TYPELAYOUT_ENTRY(BaseTypeInfo, Tag) \
(MR_BASE_TYPEINFO_GET_TYPELAYOUT(BaseTypeInfo)[(Tag)])
#define MR_BASE_TYPEINFO_GET_TYPE_ARITY(BaseTypeInfo) \
(((Word *) (BaseTypeInfo))[OFFSET_FOR_COUNT])
#define MR_BASE_TYPEINFO_GET_TYPE_NAME(BaseTypeInfo) \
(((String *) (BaseTypeInfo))[OFFSET_FOR_TYPE_NAME])
#define MR_BASE_TYPEINFO_GET_TYPE_MODULE_NAME(BaseTypeInfo) \
(((String *) (BaseTypeInfo))[OFFSET_FOR_TYPE_MODULE_NAME])
/*---------------------------------------------------------------------------*/
#if 0
/* XXX: We should use structs to represent the various
** data structures in the functors and layouts.
**
** To implement this:
** 1. The code that uses the data in the library and
** runtime should be modified to use the above access
** macros
** 2. Then we can simplify the ordering of the data
** structures (for example, put variable length fields
** last)
** 3. Then we can create structs for them.
**
** Some examples are below, (no guarantees of correctness).
**
** Note that enum_vectors have already been handled in this way.
*/
/*
** ** IMPORTANT: the layout in memory of the following
** struct must match the way that the Mercury compiler
** generates code for it.
*/
typedef struct {
Word arity;
Word arg1;
/* other arguments follow, there are arity of them,
** then followed by functor name, and functor tag.
** Word arg2;
** ...
** Word argarity;
** ConstString functorname;
** Word tag;
*/
} MR_TypeLayout_SimpleVector;
typedef struct {
Word arity;
Word arg_pseudo_type_infos[1]; /* variable-sized array */
/* actualy length is `arity', not 1 */
} MR_TypeLayout_part1;
typedef struct {
ConstString name;
Word arg_layouts[1]; /* variable-sized array */
/* actualy length is `arity', not 1 */
} MR_TypeLayout_part2;
typedef MR_TypeLayout_part1 MR_TypeLayout;
#endif
/*---------------------------------------------------------------------------*/
/*
** definitions for accessing the representation of the
** Mercury `array' type
*/
typedef struct {
Integer size;
Word elements[1]; /* really this is variable-length */
} MR_ArrayType;
#define MR_make_array(sz) ((MR_ArrayType *) make_many(Word, (sz) + 1))
/*---------------------------------------------------------------------------*/
#endif /* not TYPEINFO_H */
#include "mercury_type_info.h"

View File

@@ -4,85 +4,4 @@
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** wrapper.h - defines the interface to wrapper.mod.
** See wrapper.mod for documentation.
*/
#ifndef WRAPPER_H
#define WRAPPER_H
#include <stddef.h> /* for `size_t' */
#include "std.h" /* for `bool' */
/*
** 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);
/*
** 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.
*/
extern Code * program_entry_point; /* normally mercury__main_2_0; */
extern void (*MR_library_initializer)(void);
extern void (*MR_library_finalizer)(void);
extern void (*address_of_mercury_init_io)(void);
extern void (*address_of_init_modules)(void);
#ifdef CONSERVATIVE_GC
extern void (*address_of_init_gc)(void);
#endif
extern void do_init_modules(void);
extern const char * 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 heap_size;
extern size_t detstack_size;
extern size_t nondstack_size;
extern size_t solutions_heap_size;
extern size_t trail_size;
/* sizes of the red zones */
extern size_t heap_zone_size;
extern size_t detstack_zone_size;
extern size_t nondstack_zone_size;
extern size_t solutions_heap_zone_size;
extern size_t trail_zone_size;
/* size of the primary cache */
extern size_t pcache_size;
extern int r1val;
extern int r2val;
extern int r3val;
extern bool check_space;
extern int time_at_start;
extern int time_at_last_stat;
#endif /* not WRAPPER_H */
#include "mercury_wrapper.h"

View File

@@ -24,7 +24,7 @@
#include <ctype.h>
#include <errno.h>
#include "getopt.h"
#include "conf.h"
#include "mercury_conf.h"
#include "std.h"
/* --- adjustable limits --- */