mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
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:
2
Makefile
2
Makefile
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
27
configure.in
27
configure.in
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
124
runtime/calls.h
124
runtime/calls.h
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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"
|
||||
|
||||
|
||||
131
runtime/debug.h
131
runtime/debug.h
@@ -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"
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
144
runtime/engine.h
144
runtime/engine.h
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
580
runtime/goto.h
580
runtime/goto.h
@@ -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"
|
||||
|
||||
187
runtime/heap.h
187
runtime/heap.h
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
229
runtime/memory.h
229
runtime/memory.h
@@ -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
130
runtime/mercury_calls.h
Normal 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 */
|
||||
@@ -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
395
runtime/mercury_context.h
Normal 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
137
runtime/mercury_debug.h
Normal 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
|
||||
|
||||
65
runtime/mercury_deep_copy.h
Normal file
65
runtime/mercury_deep_copy.h
Normal 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
71
runtime/mercury_dlist.h
Normal 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
22
runtime/mercury_dummy.h
Normal 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
|
||||
@@ -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
149
runtime/mercury_engine.h
Normal 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 */
|
||||
@@ -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
29
runtime/mercury_getopt.h
Normal 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
585
runtime/mercury_goto.h
Normal 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
192
runtime/mercury_heap.h
Normal 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 */
|
||||
@@ -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
68
runtime/mercury_imp.h
Normal 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
102
runtime/mercury_init.h
Normal 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 */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@@ -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
33
runtime/mercury_label.h
Normal 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 */
|
||||
@@ -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
234
runtime/mercury_memory.h
Normal 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
70
runtime/mercury_misc.h
Normal 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 */
|
||||
78
runtime/mercury_overflow.h
Normal file
78
runtime/mercury_overflow.h
Normal 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
49
runtime/mercury_prof.h
Normal 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 */
|
||||
30
runtime/mercury_prof_mem.h
Normal file
30
runtime/mercury_prof_mem.h
Normal 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
112
runtime/mercury_regorder.h
Normal 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
165
runtime/mercury_regs.h
Normal 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 */
|
||||
90
runtime/mercury_spinlock.h
Normal file
90
runtime/mercury_spinlock.h
Normal 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
175
runtime/mercury_stacks.h
Normal 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
68
runtime/mercury_std.h
Normal 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
42
runtime/mercury_table.h
Normal 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
110
runtime/mercury_tags.h
Normal 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
47
runtime/mercury_timing.h
Normal 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 */
|
||||
@@ -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
788
runtime/mercury_type_info.h
Normal 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 */
|
||||
@@ -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*)
|
||||
|
||||
@@ -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
88
runtime/mercury_wrapper.h
Normal 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 */
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
160
runtime/regs.h
160
runtime/regs.h
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
170
runtime/stacks.h
170
runtime/stacks.h
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
105
runtime/tags.h
105
runtime/tags.h
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 --- */
|
||||
|
||||
Reference in New Issue
Block a user