for review: reorganize label table, reduce executable sizes

Zoltan Somogyi zs at cs.mu.OZ.AU
Thu Jun 25 15:27:34 AEST 1998


Fergus, please review this.

Reorganize the label table to better fit the needs of accurate gc
and the tracer, and reduce the size of executables.

With these changes, the size of hello world, compiled with static
Mercury libraries but dynamic C libraries, goes from 150+ Kb to
138+ Kb, much of which is beyond our control (e.g. Boehm gc).

Estimated hours taken: 20

runtime/mercury_label.[ch]:
	The old label table contained both entry labels and internal labels,
	even though they had different kinds of layouts associated with them
	(proc layouts and label layouts respectively). The two kinds of labels
	have different usage patterns. Internal labels are needed for stack
	walking, which requires random access by exact label address. Entry
	labels are needed for finding which procedure a program counter is in
	for accurate GC, which requires lower-bound inexact search.

	The module now has two separate data structures for the two
	different kinds of labels. Internal labels are in a hash table,
	as before. Entry labels are in an array (resized on demand),
	which is sorted for binary search. The entry label array and
	its associated functions are present only if they are needed.

runtime/mercury_goto.h:
	Call the new functions in mercury_label.c from the
	init_{local,label,entry}{,_sl} macros.

runtime/mercury_misc.[ch]
	Use the new functions in mercury_label. Fix some software rot,
	so that the code now compiles with MR_DEBUG_GOTOS. (It still does not
	compile with MR_LOWLEVEL_DEBUG, but the fix for that would conflict
	with Tom's planned change to zone handling, so that fix should be
	done after Tom is done.)

	Note that mercury_misc.c still defines newmem() and oldmem()
	although they are declared in mercury_std.h.

runtime/mercury_stack_trace.c:
	Use the new functions in mercury_label.

runtime/mercury_table.[ch]:
	Add a new traversal predicate to support a new function in
	mercury_label.c. (That function is not used yet, but will be soon.)

runtime/mercury_trace.[ch]:
runtime/mercury_trace_permanent.[ch]:
	Split the old mercury_trace module into two. The functions and
	variables that will always be linked in (because they are referenced
	from modules such as mercury_wrapper which are always needed) are
	now in mercury_trace_permanent; the other functions and variables
	stay in mercury_trace. This way, mercury_trace.o will be linked in
	only if some module was compiled with execution tracing. Since
	mercury_trace.o drags in mercury_trace_internal.o which drags in
	everything needed for printing arbitrary terms (which is a lot),
	this can be a significant win.

runtime/Mmakefile:
	Include the new module in the library.

runtime/mercury_wrapper.c:
runtime/mercury_conf_param.h:
	Remove some obsolete MERCURY_OPTIONS options, which would be
	difficult to support with the new label table.

	Replace the long help message for malformed MERCURY_OPTIONS
	environment variables with a pointer to the appropriate manual.
	This saves about 1 Kb on every executable.

util/mkinit.c:
	Add a new flag, -i. If this flag is given, include the initialization
	code regardless of grade. If it is not given, include the init code
	only if the grade requires it.

	The -i should be given if you want the executable to support stack
	tracing, or uplevel printing in execution tracing, at the cost of
	making the executable link in the init functions of all the modules
	in the library.

	Put the option handling code in alphabetical order.

scripts/c2init.in:
	Pass through the -i flag to mkinit.

	Put the option handling code in alphabetical order.

compiler/mercury_compile.m:
	If the trace level specifies any kind of tracing, pass -i to c2init.

tests/debugger/Mmakefile:
	Add -i to the c2init flags.

tests/debugger/*
	Update other half the test cases (those which assume a traced
	library) to conform to the changes in the debugger interface.
	The others were updated earlier.

Zoltan.

Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.100
diff -u -r1.100 mercury_compile.m
--- mercury_compile.m	1998/06/18 06:06:37	1.100
+++ mercury_compile.m	1998/06/25 06:08:10
@@ -2330,7 +2330,13 @@
 	    % create the initialization C file
 	    maybe_write_string(Verbose, "% Creating initialization file...\n"),
 	    join_module_list(Modules, ".m", ["> ", InitCFileName], MkInitCmd0),
-	    { string__append_list(["c2init " | MkInitCmd0], MkInitCmd) },
+	    globals__io_get_trace_level(TraceLevel),
+	    { trace_level_trace_interface(TraceLevel, yes) ->
+		CmdPrefix = "c2init -i "
+	    ;
+		CmdPrefix = "c2init "
+	    },
+	    { string__append_list([CmdPrefix | MkInitCmd0], MkInitCmd) },
 	    invoke_system_command(MkInitCmd, MkInitOK),
 	    maybe_report_stats(Stats),
 	    ( { MkInitOK = no } ->
Index: runtime/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/Mmakefile,v
retrieving revision 1.30
diff -u -r1.30 Mmakefile
--- Mmakefile	1998/06/09 02:07:45	1.30
+++ Mmakefile	1998/06/25 06:47:44
@@ -14,7 +14,7 @@
 #-----------------------------------------------------------------------------#
 
 CFLAGS		= -I$(MERCURY_DIR)/runtime -I$(MERCURY_DIR)/boehm_gc -g \
-		  $(DLL_CFLAGS) $(EXTRA_CFLAGS) 
+		  $(DLL_CFLAGS) $(EXTRA_CFLAGS)
 MGNUC		= MERCURY_C_INCL_DIR=. $(SCRIPTS_DIR)/mgnuc
 MGNUCFLAGS	= --no-ansi $(EXTRA_MGNUCFLAGS) $(CFLAGS)
 MOD2C		= $(SCRIPTS_DIR)/mod2c
@@ -69,6 +69,7 @@
 			mercury_trace.h		\
 			mercury_trace_external.h \
 			mercury_trace_internal.h \
+			mercury_trace_permanent.h \
 			mercury_trace_util.h	\
 			mercury_trail.h		\
 			mercury_types.h		\
@@ -120,6 +121,7 @@
 			mercury_trace.c		\
 			mercury_trace_external.c \
 			mercury_trace_internal.c \
+			mercury_trace_permanent.c \
 			mercury_trace_util.c	\
 			mercury_trail.c 	\
 			mercury_type_info.c	\
Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.5
diff -u -r1.5 mercury_conf_param.h
--- mercury_conf_param.h	1998/06/08 08:26:58	1.5
+++ mercury_conf_param.h	1998/06/19 06:15:43
@@ -145,16 +145,6 @@
 ** Enables profiling of memory usage.
 */
 
-/*
-** Miscellaneous options:
-**
-** MR_CHOOSE_ENTRY_POINT
-**	Enables support for the `-w' (entry point) command
-**	in the MERCURY_OPTIONS environment variable.
-**	(`-w' also happens to work if you set certain other
-**	options instead, include MR_LOWLEVEL_DEBUG.)
-*/
-
 /*---------------------------------------------------------------------------*/
 /*
 ** Settings of configuration parameters which can be passed on
Index: runtime/mercury_goto.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_goto.h,v
retrieving revision 1.10
diff -u -r1.10 mercury_goto.h
--- mercury_goto.h	1998/06/08 08:27:01	1.10
+++ mercury_goto.h	1998/06/23 08:02:17
@@ -12,6 +12,7 @@
 #include "mercury_conf.h"
 #include "mercury_types.h"	/* for `Code *' */
 #include "mercury_debug.h"	/* for debuggoto() */
+#include "mercury_label.h"	/* for insert_{entry,internal}_label() */
 
 #define paste(a,b) a##b
 #define stringify(string) #string
@@ -19,13 +20,15 @@
 #define skip(label) paste(skip_,label)
 
 #if defined(MR_USE_STACK_LAYOUTS)
-  #define MR_STACK_LAYOUT(label)        (Word *) (Word) \
+  #define MR_ENTRY_LAYOUT(label)	(MR_Stack_Layout_Entry *) (Word) \
 	&(paste(mercury_data__layout__,label))
+  #define MR_INTERNAL_LAYOUT(label)	(MR_Stack_Layout_Label *) (Word) \
+	&(paste(mercury_data__layout__,label))
 #else
-  #define MR_STACK_LAYOUT(label)	(Word *) NULL
+  #define MR_ENTRY_LAYOUT(label)	(MR_Stack_Layout_Entry *) NULL
+  #define MR_INTERNAL_LAYOUT(label)	(MR_Stack_Layout_Label *) NULL
 #endif
 
-
 /*
 ** Taking the address of a label can inhibit gcc's optimization,
 ** because it assumes that anything can jump there.
@@ -40,25 +43,27 @@
 */
 
 #if defined(MR_INSERT_LABELS)
-  #define make_label(n, a, l)		make_entry(n, a, l)
-  #define make_label_sl(n, a, l)	make_entry_sl(n, a, l)
+  #define make_label(n, a, l)		MR_insert_internal_label(n, a, NULL)
+  #define make_label_sl(n, a, l)	\
+  		MR_insert_internal_label(n, a, MR_INTERNAL_LAYOUT(l))
 #else
   #define make_label(n, a, l)		/* nothing */
   #define make_label_sl(n, a, l)	/* nothing */
 #endif
 
 #if defined(MR_INSERT_LABELS) || defined(PROFILE_CALLS)
-  #define make_local(n, a, l)		make_entry(n, a, l)
-  #define make_local_sl(n, a, l)	make_entry_sl(n, a, l)
+  #define make_local(n, a, l)		MR_insert_internal_label(n, a, NULL)
+  #define make_local_sl(n, a, l)	\
+  		MR_insert_internal_label(n, a, MR_INTERNAL_LAYOUT(l))
 #else 
   #define make_local(n, a, l)		/* nothing */
   #define make_local_sl(n, a, l)	/* nothing */
 #endif
 
-#if defined(MR_INSERT_LABELS) || defined(PROFILE_CALLS) \
-		|| defined(MR_CHOOSE_ENTRY_POINT)
-  #define make_entry(n, a, l)		insert_entry(n, a, NULL)
-  #define make_entry_sl(n, a, l)	insert_entry(n, a, MR_STACK_LAYOUT(l))
+#if defined(MR_INSERT_LABELS) || defined(PROFILE_CALLS)
+  #define make_entry(n, a, l)		MR_insert_entry_label(n, a, NULL)
+  #define make_entry_sl(n, a, l)	\
+  		MR_insert_entry_label(n, a, MR_ENTRY_LAYOUT(l))
 #else
   #define make_entry(n, a, l)		/* nothing */
   #define make_entry_sl(n, a, l)	/* nothing */
Index: runtime/mercury_label.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_label.c,v
retrieving revision 1.6
diff -u -r1.6 mercury_label.c
--- mercury_label.c	1998/03/16 12:23:30	1.6
+++ mercury_label.c	1998/06/23 07:52:36
@@ -23,44 +23,75 @@
 #include	"mercury_engine.h"	/* for `progdebug' */
 #include	"mercury_wrapper.h"	/* for do_init_modules() */
 
-static	const void	*entry_name(const void *entry);
-static	const void	*entry_addr(const void *entry);
-static	bool		equal_name(const void *name1, const void *name2);
+/*
+** We record information about entry labels in an array that
+** we sort by code address once all the entry labels have been inserted.
+** Space for the array is provided by malloc, and it is expanded when
+** needed.
+**
+** This array is needed only by accurate garbage collection and when
+** doing low-level debugging.
+*/
+
+#ifdef	MR_NEED_ENTRY_LABEL_ARRAY
+
+#define	INIT_ENTRY_SIZE	(1 << 8)
+
+static	int		compare_entry_by_addr(const void *e1, const void *e2);
+
+static	MR_Entry	*entry_array;
+static	int		entry_array_size;	/* # of entries allocated */
+static	int		entry_array_next;	/* # of entries used      */
+static	bool		entry_array_sorted;
+
+#endif	/* MR_NEED_ENTRY_LABEL_ARRAY */
+
+/*
+** We record information about internal labels in a hash table
+** that is indexed by the code address of the label.
+**
+** This table is used by stack tracing and execution tracing.
+** Since execution tracing and hence stack tracing can be required
+** in any grade, we always include this table.
+*/
+
+#define	INTERNAL_SIZE	(1 << 16)	/* 64k */
+
+static	const void	*internal_addr(const void *internal);
 static	bool		equal_addr(const void *addr1, const void *addr2);
-static	int		hash_name(const void *name);
 static	int		hash_addr(const void *addr);
 
-int	entry_table_size = (1 << 16);	/* 64k */
+static	Table		internal_addr_table = {INTERNAL_SIZE, NULL,
+				internal_addr, hash_addr, equal_addr};
 
-Table	entry_name_table =
-	{0, NULL, entry_name, hash_name, equal_name};
-Table	entry_addr_table =
-	{0, NULL, entry_addr, hash_addr, equal_addr};
-
 void 
-do_init_entries(void)
+MR_do_init_label_tables(void)
 {
-	static bool done = FALSE;
+	static	bool	done = FALSE;
+
 	if (!done) {
-		entry_name_table.ta_size = entry_table_size;
-		entry_addr_table.ta_size = entry_table_size;
-		init_table(entry_name_table);
-		init_table(entry_addr_table);
+#ifdef	MR_NEED_ENTRY_LABEL_ARRAY
+		entry_array_next = 0;
+		entry_array_size = INIT_ENTRY_SIZE;
+		entry_array_sorted = TRUE;
+		entry_array = malloc(entry_array_size * sizeof(MR_Entry));
+#endif
+
+		init_table(internal_addr_table);
+
 		done = TRUE;
 	}
 }
 
-Label *
-insert_entry(const char *name, Code *addr, Word *entry_layout_info)
-{
-	Label	*entry;
+#ifdef	MR_NEED_ENTRY_LABEL_INFO
 
-	do_init_entries();
+static	int	compare_entry_addr(const void *e1, const void *e2);
 
-	entry = make(Label);
-	entry->e_name  = name;
-	entry->e_addr  = addr;
-	entry->e_layout = entry_layout_info;
+void
+MR_insert_entry_label(const char *name, Code *addr,
+	MR_Stack_Layout_Entry *entry_layout)
+{
+	MR_do_init_label_tables();
 
 #ifdef	PROFILE_CALLS
 	if (MR_profiling) MR_prof_output_addr_decl(name, addr);
@@ -68,74 +99,130 @@
 
 #ifdef	MR_LOWLEVEL_DEBUG
 	if (progdebug) {
-		printf("inserting label %s at %p\n", name, addr);
+		printf("recording entry label %s at %p\n", name, addr);
 	}
 #endif
+
+#ifdef	MR_NEED_ENTRY_LABEL_ARRAY
 
-	if (insert_table(entry_name_table, entry)) {
-		printf("duplicated label name %s\n", name);
+	if (entry_array_next >= entry_array_size) {
+		entry_array_size *= 2;
+		if (realloc(entry_array, entry_array_size * sizeof(MR_Entry))
+				== NULL) {
+			fatal_error("run out of memory for entry label array");
+		}
 	}
 
-	/* two labels at same location will happen quite often */
-	/* when the code generated between them turns out to be empty */
+	entry_array[entry_array_next].e_addr = addr;
+	entry_array[entry_array_next].e_name = name;
+	entry_array[entry_array_next].e_layout = entry_layout;
+	entry_array_next++;
+	entry_array_sorted = FALSE;
+#endif
+}
+
+#endif
 
-	(void) insert_table(entry_addr_table, entry);
+#ifdef	MR_NEED_ENTRY_LABEL_ARRAY
 
-	return entry;
+static int
+compare_entry_addr(const void *e1, const void *e2)
+{
+	const MR_Entry	*entry1;
+	const MR_Entry	*entry2;
+
+	entry1 = (const MR_Entry *) e1;
+	entry2 = (const MR_Entry *) e2;
+
+	if (entry1->e_addr > entry2->e_addr) {
+		return 1;
+	} else if (entry1->e_addr < entry2->e_addr) {
+		return -1;
+	} else {
+		return 0;
+	}
 }
 
-Label *
-lookup_label_addr(const Code *addr)
+MR_Entry *
+MR_prev_entry_by_addr(const Code *addr)
 {
-	do_init_entries();
-	do_init_modules();
-#ifdef	MR_LOWLEVEL_DEBUG
-	if (progdebug) {
-		printf("looking for label at %p\n", addr);
+	int	lo;
+	int	hi;
+	int	mid;
+	int	i;
+
+	if (!entry_array_sorted) {
+		qsort(entry_array, entry_array_next, sizeof(MR_Entry),
+			compare_entry_addr);
 	}
-#endif
+
+	lo = 0;
+	hi = entry_array_next-1;
+
+	while (lo <= hi) {
+		mid = (lo + hi) / 2;
+		if (entry_array[mid].e_addr == addr) {
+			return &entry_array[mid];
+		} else if (entry_array[mid].e_addr < addr) {
+			lo = mid + 1;
+		} else {
+			hi = mid - 1;
+		}
+	}
 
-	return (Label *) lookup_table(entry_addr_table, addr);
+	if (entry_array[lo].e_addr < addr) {
+		return &entry_array[lo];
+	} else {
+		return &entry_array[lo-1];
+	}
 }
 
-Label *
-lookup_label_name(const char *name)
-{
-	do_init_entries();
-	do_init_modules();
+#endif
+
+void
+MR_insert_internal_label(const char *name, Code *addr,
+	MR_Stack_Layout_Label *label_layout)
+{
+	MR_Internal	*internal;
+
+	MR_do_init_label_tables();
+
+	internal = make(MR_Internal);
+	internal->i_addr = addr;
+	internal->i_layout = label_layout;
+	internal->i_name = name;
+
 #ifdef	MR_LOWLEVEL_DEBUG
 	if (progdebug) {
-		printf("looking for label %s\n", name);
+		printf("inserting internal label %s at %p\n", name, addr);
 	}
 #endif
 
-	return (Label *) lookup_table(entry_name_table, name);
+	/* two labels at same location will happen quite often */
+	/* when the code generated between them turns out to be empty */
+
+	(void) insert_table(internal_addr_table, internal);
 }
 
-List *
-get_all_labels(void)
+MR_Internal *
+MR_lookup_internal_by_addr(const Code *addr)
 {
-	do_init_entries();
+	MR_do_init_label_tables();
 	do_init_modules();
-	return get_all_entries(entry_name_table);
-}
 
-static const void *
-entry_name(const void *entry)
-{
-	return (const void *) (((const Label *) entry)->e_name);
-}
+#ifdef	MR_LOWLEVEL_DEBUG
+	if (progdebug) {
+		printf("looking for internal label at %p\n", addr);
+	}
+#endif
 
-static const void *
-entry_addr(const void *entry)
-{
-	return (const void *) (((const Label *) entry)->e_addr);
+	return (MR_Internal *) lookup_table(internal_addr_table, addr);
 }
 
-static bool 
-equal_name(const void *name1, const void *name2)
+static const void *
+internal_addr(const void *internal)
 {
-	return streq(((const char *) name1), ((const char *) name2));
+	return (const void *) (((const MR_Internal *) internal)->i_addr);
 }
 
 static bool 
@@ -145,13 +232,13 @@
 }
 
 static int 
-hash_name(const void *name)
+hash_addr(const void *addr)
 {
-	return str_to_int(((const char *) name)) % entry_table_size;
+	return (((Unsigned) addr) >> 3) % INTERNAL_SIZE;
 }
 
-static int 
-hash_addr(const void *addr)
+void
+MR_process_all_internal_labels(void f(const void *))
 {
-	return (((Unsigned) addr) >> 3) % entry_table_size;
+	process_all_entries(internal_addr_table, f);
 }
Index: runtime/mercury_label.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_label.h,v
retrieving revision 1.4
diff -u -r1.4 mercury_label.h
--- mercury_label.h	1998/04/21 05:51:37	1.4
+++ mercury_label.h	1998/06/23 07:55:51
@@ -15,24 +15,46 @@
 #ifndef	MERCURY_LABEL_H
 #define	MERCURY_LABEL_H
 
-#include "mercury_types.h"	/* for `Code *' */
-#include "mercury_dlist.h"		/* for `List' */
+#include "mercury_types.h"		/* for `Code *' */
+#include "mercury_dlist.h" 		/* for `List' */
+#include "mercury_stack_layout.h"	/* for `MR_Stack_Layout_*' */
 
-typedef struct s_label {
-	const char	*e_name;   /* name of the procedure	     */
-	Code		*e_addr;   /* address of the code	     */
-	Word		*e_layout; /* layout info for the label      */
-} Label;
-
-extern	void	do_init_entries(void);
-extern	Label	*insert_entry(const char *name, Code *addr,
-			Word * entry_layout_info);
-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 */
+#if     defined(NATIVE_GC) || defined(MR_DEBUG_GOTOS)
+#define	MR_NEED_ENTRY_LABEL_ARRAY
+#endif
+
+#if     defined(MR_NEED_ENTRY_LABEL_ARRAY) || defined(PROFILE_CALLS)
+#define	MR_NEED_ENTRY_LABEL_INFO
+#endif
+
+typedef struct s_entry {
+	Code			*e_addr;
+	MR_Stack_Layout_Entry	*e_layout;
+	const char		*e_name;
+} MR_Entry;
+
+typedef struct s_internal {
+	Code			*i_addr;
+	MR_Stack_Layout_Label	*i_layout;
+	const char		*i_name;
+} MR_Internal;
+
+extern	void		MR_do_init_label_tables(void);
+
+#ifdef	MR_NEED_ENTRY_LABEL_INFO
+extern	void		MR_insert_entry_label(const char *name, Code *addr,
+				MR_Stack_Layout_Entry *entry_layout);
+#else
+#define	MR_insert_entry_label(n, a, l)	/* nothing */
+#endif	/* not MR_NEED_ENTRY_LABEL_INFO */
+
+#ifdef	MR_NEED_ENTRY_LABEL_ARRAY
+extern	MR_Entry	*MR_prev_entry_by_addr(const Code *addr);
+#endif	/* MR_NEED_ENTRY_LABEL_ARRAY */
+
+extern	void		MR_insert_internal_label(const char *name, Code *addr,
+				MR_Stack_Layout_Label *label_layout);
+extern	MR_Internal	*MR_lookup_internal_by_addr(const Code *addr);
+extern	void		MR_process_all_internal_labels(void f(const void *));
 
 #endif /* not MERCURY_LABEL_H */
Index: runtime/mercury_misc.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_misc.c,v
retrieving revision 1.7
diff -u -r1.7 mercury_misc.c
--- mercury_misc.c	1998/06/09 02:08:11	1.7
+++ mercury_misc.c	1998/06/23 07:34:23
@@ -8,6 +8,7 @@
 #include	"mercury_dlist.h"
 #include	"mercury_regs.h"
 #include	"mercury_trace.h"
+#include	"mercury_label.h"
 #include	"mercury_misc.h"
 
 #include	<stdio.h>
@@ -214,19 +215,13 @@
 
 #endif /* defined(MR_LOWLEVEL_DEBUG) */
 
-#if defined(MR_DEBUG_GOTOS)
+#ifdef MR_DEBUG_GOTOS
 
 void 
 goto_msg(/* const */ Code *addr)
 {
 	printf("\ngoto ");
 	printlabel(addr);
-
-	if (detaildebug) {
-		printregs("registers at goto");
-	}
-
-	return;
 }
 
 void 
@@ -254,7 +249,7 @@
 
 /*--------------------------------------------------------------------*/
 
-#if defined(MR_DEBUG_GOTOS)
+#ifdef MR_LOWLEVEL_DEBUG
 
 /* debugging printing tools */
 
@@ -410,16 +405,25 @@
 void 
 printlabel(/* const */ Code *w)
 {
-	Label	*label;
+	MR_Internal	*internal;
 
-	label = lookup_label_addr(w);
-	if (label != NULL) {
-		printf("label %s (0x%p)\n", label->e_name, w);
+	internal = MR_lookup_internal_by_addr(w);
+	if (internal != NULL) {
+		printf("label %s (0x%p)\n", internal->i_name, w);
 	} else {
+#ifdef	MR_DEBUG_GOTOS
+		MR_Entry	*entry;
+		entry = MR_prev_entry_by_addr(w);
+		if (entry->e_addr == w) {
+			printf("label %s (0x%p)\n", entry->e_name, w);
+		} else {
+			printf("label UNKNOWN (0x%p)\n", w);
+		}
+#else
 		printf("label UNKNOWN (0x%p)\n", w);
+#endif	/* not MR_DEBUG_GOTOS */
 	}
 }
-
 
 void *
 newmem(size_t n)
Index: runtime/mercury_misc.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_misc.h,v
retrieving revision 1.6
diff -u -r1.6 mercury_misc.h
--- mercury_misc.h	1998/06/09 02:08:12	1.6
+++ mercury_misc.h	1998/06/23 07:16:08
@@ -17,7 +17,6 @@
 #include "mercury_types.h"	/* for `Code *' */
 
 #ifdef MR_LOWLEVEL_DEBUG
-
 extern	void	mkframe_msg(void);
 extern	void	modframe_msg(void);
 extern	void	succeed_msg(void);
@@ -35,16 +34,13 @@
 extern	void	push_msg(Word val, const Word *addr);
 extern	void	pop_msg(Word val, const Word *addr);
 #endif
-
-#if defined(MR_DEBUG_GOTOS)
 
+#ifdef MR_DEBUG_GOTOS
 extern	void	goto_msg(/* const */ Code *addr);
 extern	void	reg_msg(void);
-
 #endif
 
 #ifdef MR_LOWLEVEL_DEBUG
-
 extern	void	printint(Word n);
 extern	void	printstring(const char *s);
 extern	void	printheap(const Word *h);
@@ -55,12 +51,10 @@
 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
@@ -76,6 +70,6 @@
 ** XXX We should fix this eventually by using -fno-builtin since pragma
 ** c_code may call the builtin functions.
 */
-void MR_memcpy(char *dest, const char *src, size_t nbytes);
+extern	void	MR_memcpy(char *dest, const char *src, size_t nbytes);
 
 #endif /* not MERCURY_MISC_H */
Index: runtime/mercury_stack_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.c,v
retrieving revision 1.9
diff -u -r1.9 mercury_stack_trace.c
--- mercury_stack_trace.c	1998/06/18 06:08:05	1.9
+++ mercury_stack_trace.c	1998/06/19 07:23:03
@@ -150,11 +150,12 @@
 	Word **stack_trace_sp_ptr, Word **stack_trace_curfr_ptr,
 	const char **problem_ptr)
 {
-	Label			*label;
+	MR_Internal		*label;
 	MR_Live_Lval		location;
 	MR_Stack_Layout_Label	*label_layout;
 	MR_Lval_Type		type;
-	int			number, determinism;
+	int			number;
+	int			determinism;
 	Code			*success;
 
 	*return_label_layout = NULL;
@@ -192,13 +193,13 @@
 		return STEP_OK;
 	}
 
-	label = lookup_label_addr(success);
+	label = MR_lookup_internal_by_addr(success);
 	if (label == NULL) {
 		*problem_ptr = "reached label with no stack trace info";
 		return STEP_ERROR_AFTER;
 	}
 
-	label_layout = (MR_Stack_Layout_Label *) label->e_layout;
+	label_layout = (MR_Stack_Layout_Label *) label->i_layout;
 	if (label_layout == NULL) {
 		*problem_ptr = "reached label with no stack layout info";
 		return STEP_ERROR_AFTER;
Index: runtime/mercury_table.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_table.c,v
retrieving revision 1.3
diff -u -r1.3 mercury_table.c
--- mercury_table.c	1997/11/23 09:31:50	1.3
+++ mercury_table.c	1998/06/23 07:50:07
@@ -120,6 +120,23 @@
 }
 
 /*
+**	Process all table entries with the specified function.
+*/
+
+void
+tab_process_all_entries(const Table *table, void f(const void *))
+{
+	reg	List	*ptr;
+	reg	int	i;
+
+	for (i = 0; i < table->ta_size; i++) {
+		for_list (ptr, table->ta_store[i]) {
+			(*f)(ldata(ptr));
+		}
+	}
+}
+
+/*
 **	Convert a string to a positive int. The return value
 **	mod the table size is a good hash value.
 */
Index: runtime/mercury_table.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_table.h,v
retrieving revision 1.4
diff -u -r1.4 mercury_table.h
--- mercury_table.h	1998/05/17 07:03:14	1.4
+++ mercury_table.h	1998/06/23 07:48:58
@@ -28,20 +28,22 @@
 						    /* 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	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	process_all_entries(t, f)	tab_process_all_entries(&t, f)
+#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))
+#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	void	tab_process_all_entries(const Table *, void f(const void *));
 extern	int	tab_str_to_int(const char *);
 
 #endif /* not MERCURY_TABLE_H */
Index: runtime/mercury_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace.c,v
retrieving revision 1.13
diff -u -r1.13 mercury_trace.c
--- mercury_trace.c	1998/05/16 07:28:21	1.13
+++ mercury_trace.c	1998/06/23 08:33:07
@@ -31,71 +31,6 @@
 #include <stdio.h>
 #include <unistd.h>		/* for the write system call */
 
-/*
-** Do we want to use the debugger within this process, or do want to use
-** the Opium-style trace analyzer debugger implemented by an external process.
-** This variable is set in mercury_wrapper.c and never modified afterwards.
-*/
-
-MR_trace_type	MR_trace_handler = MR_TRACE_INTERNAL;
-
-/*
-** Compiler generated tracing code will check whether MR_trace_enabled is true,
-** before calling MR_trace. For now, and until we implement interface tracing,
-** MR_trace_enabled should keep the same value throughout the execution of
-** the entire program after being set in mercury_wrapper.c. There is one
-** exception to this: the Mercury routines called as part of the functionality
-** of the tracer itself (e.g. the term browser) should always be executed
-** with MR_trace_enabled set to FALSE.
-*/
-
-bool		MR_trace_enabled = FALSE;
-
-/*
-** MR_trace_call_seqno counts distinct calls. The prologue of every
-** procedure assigns the current value of this counter as the sequence number
-** of that invocation and increments the counter. This is the only way that
-** MR_trace_call_seqno is modified.
-**
-** MR_trace_call_depth records the current depth of the call tree. The prologue
-** of every procedure assigns the current value of this variable plus one
-** as the depth of that invocation. Just before making a call, the caller
-** will set MR_trace_call_depth to its own remembered depth value. 
-** These are the only ways in which MR_trace_call_depth is modified.
-**
-** Although neither MR_trace_call_seqno nor MR_trace_call_depth are used
-** directly in this module, the seqno and depth arguments of MR_trace
-** always derive their values from the saved values of these two global
-** variables.
-*/
-
-Unsigned	MR_trace_call_seqno = 0;
-Unsigned	MR_trace_call_depth = 0;
-
-/*
-** MR_trace_event_number is a simple counter of events. This is used in
-** two places: here, for display to the user and for skipping a given number
-** of events, and when printing an abort message, so that the programmer
-** can zero in on the source of the problem more quickly.
-*/
-
-Unsigned	MR_trace_event_number = 0;
-
-/*
-** MR_trace_from_full is a boolean that is set before every call;
-** it states whether the caller is being fully traced, or only interface
-** traced. If the called code is interface traced, it will generate
-** call, exit and fail trace events only if MR_trace_from_full is true.
-** (It will never generate internal events.) If the called code is fully
-** traced, it will always generate all trace events, external and internal,
-** regardless of the setting of this variable on entry.
-**
-** The initial value is set to TRUE to allow the programmer to gain
-** control in the debugger when main/2 is called.
-*/
-
-Bool	MR_trace_from_full = 1;
-
 static	MR_trace_cmd_info	MR_trace_ctrl = { MR_CMD_GOTO, 0, 0, FALSE };
 
 static	void	MR_trace_event(MR_trace_cmd_info *cmd,
@@ -107,40 +42,6 @@
 			MR_trace_port port, Unsigned seqno, Unsigned depth,
 			const char *path, int max_r_num);
 
-void
-MR_trace_init(void)
-{
-#ifdef MR_USE_EXTERNAL_DEBUGGER
-	if (MR_trace_handler == MR_TRACE_EXTERNAL)
-		MR_trace_init_external();
-#endif
-}
-
-void
-MR_trace_final(void)
-{
-#ifdef MR_USE_EXTERNAL_DEBUGGER
-	if (MR_trace_handler == MR_TRACE_EXTERNAL)
-		MR_trace_final_external();
-#endif
-}
-
-void
-MR_trace_start(bool enabled)
-{
-	MR_trace_event_number = 0;
-	MR_trace_call_seqno = 0;
-	MR_trace_call_depth = 0;
-	MR_trace_from_full = TRUE;
-	MR_trace_enabled = enabled;
-}
-
-void
-MR_trace_end(void)
-{
-	MR_trace_enabled = FALSE;
-}
-
 /*
 ** This function is called from compiled code whenever an event to be traced
 ** occurs.
@@ -261,35 +162,4 @@
 
 	MR_trace_event_internal_report(layout, port, seqno, depth, path);
 #endif
-}
-
-void
-MR_trace_report(FILE *fp)
-{
-	if (MR_trace_event_number > 0) {
-		/*
-		** This means that the executable was compiled with tracing,
-		** which implies that the user wants trace info on abort.
-		*/
-
-		fprintf(fp, "Last trace event was event #%ld.\n",
-			(long) MR_trace_event_number);
-	}
-}
-
-void
-MR_trace_report_raw(int fd)
-{
-	char	buf[80];	/* that ought to be more than long enough */
-
-	if (MR_trace_event_number > 0) {
-		/*
-		** This means that the executable was compiled with tracing,
-		** which implies that the user wants trace info on abort.
-		*/
-
-		sprintf(buf, "Last trace event was event #%ld.\n",
-			(long) MR_trace_event_number);
-		write(fd, buf, strlen(buf));
-	}
 }
Index: runtime/mercury_trace.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace.h,v
retrieving revision 1.8
diff -u -r1.8 mercury_trace.h
--- mercury_trace.h	1998/05/16 07:28:23	1.8
+++ mercury_trace.h	1998/06/23 08:32:30
@@ -13,23 +13,28 @@
 ** (b)	It defines the interface by which the internal and external debuggers
 **	can control how the tracing subsystem treats events.
 **
-** The macros and functions defined in this module are intended to be called
-** only from code generated by the Mercury compiler, and from hand-written
-** code in the Mercury runtime or the Mercury standard library.
+** The macros, functions and variables of this module are intended to be
+** referred to only from code generated by the Mercury compiler, and from
+** hand-written code in the Mercury runtime or the Mercury standard library,
+** and even then only if at least some part of the program was compiled
+** with some form of execution tracing.
+**
+** The parts of the tracing system that need to be present even when no
+** part of the program is compiled with execution tracing are in the module
+** mercury_trace_permanent.
 */
 
 #ifndef MERCURY_TRACE_H
 #define MERCURY_TRACE_H
 
+#include "mercury_trace_permanent.h"
+
 /* The interface between the tracing subsystem and compiled code. */
 
 #define	MR_trace_incr_seq()	(++MR_trace_call_seqno)
 #define	MR_trace_incr_depth()	(++MR_trace_call_depth)
 #define	MR_trace_reset_depth(d)	do { MR_trace_call_depth = (d); } while (0)
 
-extern	Word	MR_trace_call_seqno;
-extern	Word	MR_trace_call_depth;
-
 /*
 ** This enum should exactly match the definition of the `trace_port' type in
 ** library/debugger_interface.
@@ -55,51 +60,6 @@
 	const char *,		/* path to event goal within procedure */
 	int,			/* highest numbered rN register in use */
 	bool);			/* is this event supposed to be traced */
-
-/*
-** These functions will report the number of the last event,
-** if there have been some events, and will do nothing otherwise.
-*/
-
-extern	void	MR_trace_report(FILE *fp);
-extern	void	MR_trace_report_raw(int fd);
-
-/*
-** MR_trace_init() is called from mercury_runtime_init()
-** when the debuggee programs begins, to perform any initialization
-** that must be done before any traced Mercury code is executed.
-** This includes the initialization code written in Mercury as well as main.
-**
-** MR_trace_start(enabled) is called from mercury_runtime_init()
-** after the initialization code written in Mercury is executed,
-** when we are about to start executing main. The argument says
-** whether tracing is enabled for main (it is never enabled for
-** initialization and finalization routines).
-**
-** MR_trace_end() is called from mercury_runtime_terminate() just
-** after main has terminated and just before we call the finalization
-** code written in Mercury.
-**
-** MR_trace_final() is called from mercury_runtime_terminate()
-** after all Mercury code, including finalization code, has terminated.
-*/
-
-extern	void	MR_trace_init(void);
-extern	void	MR_trace_start(bool enabled);
-extern	void	MR_trace_end(void);
-extern	void	MR_trace_final(void);
-
-typedef	enum {
-	MR_TRACE_INTERNAL,
-	MR_TRACE_EXTERNAL
-} MR_trace_type;
-
-extern	MR_trace_type	MR_trace_handler;
-extern	bool		MR_trace_enabled;
-
-extern	Unsigned	MR_trace_event_number;
-
-extern	Bool		MR_trace_from_full;
 
 /* The interface between the debuggers and the tracing subsystem. */
 
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.14
diff -u -r1.14 mercury_wrapper.c
--- mercury_wrapper.c	1998/06/18 04:30:47	1.14
+++ mercury_wrapper.c	1998/06/23 08:46:19
@@ -567,27 +567,6 @@
 			usage();
 			break;
 
-		case 'L': 
-			do_init_modules();
-			break;
-
-		case 'l': {
-			List	*ptr;
-			List	*label_list;
-
-			label_list = get_all_labels();
-			for_list (ptr, label_list) {
-				Label	*label;
-				label = (Label *) ldata(ptr);
-				printf("%lu %lx %s\n",
-					(unsigned long) label->e_addr,
-					(unsigned long) label->e_addr,
-					label->e_name);
-			}
-
-			exit(0);
-		}
-
 		case 'p':
 			MR_profiling = FALSE;
 			break;
@@ -619,9 +598,6 @@
 				detstack_size = size;
 			else if (optarg[0] == 'n')
 				nondstack_size = size;
-			else if (optarg[0] == 'l')
-				entry_table_size = size *
-					1024 / (2 * sizeof(List *));
 #ifdef MR_USE_TRAIL
 			else if (optarg[0] == 't')
 				trail_size = size;
@@ -656,22 +632,6 @@
 			}
 			break;
 
-		case 'w': {
-			Label *which_label;
-
-			which_label = lookup_label_name(optarg);
-			if (which_label == NULL)
-			{
-				fprintf(stderr, "Mercury runtime: "
-					"label name `%s' unknown\n",
-					optarg);
-				exit(1);
-			}
-
-			program_entry_point = which_label->e_addr;
-
-			break;
-		}
 		case 'x':
 #ifdef CONSERVATIVE_GC
 			GC_dont_gc = TRUE;
@@ -708,54 +668,9 @@
 static void 
 usage(void)
 {
-	printf("Mercury runtime usage:\n"
-		"MERCURY_OPTIONS=\"[-hclLtxp] [-T[rvp]] [-d[abcdghs]]\n"
-        "                  [-[szt][hdn]#] [-C#] [-r#]  [-w name] [-[123]#]\"\n"
-		"-h \t\tprint this usage message\n"
-		"-c \t\tcheck cross-function stack usage\n"
-		"-l \t\tprint all labels\n"
-		"-L \t\tcheck for duplicate labels\n"
-		"-t \t\ttime program execution\n"
-		"-x \t\tdisable garbage collection\n"
-		"-p \t\tdisable profiling\n"
-		"-Tr \t\tprofile real time (using ITIMER_REAL)\n"
-		"-Tv \t\tprofile user time (using ITIMER_VIRTUAL)\n"
-		"-Tp \t\tprofile user + system time (using ITIMER_PROF)\n"
-		"-dg \t\tdebug gotos\n"
-		"-dc \t\tdebug calls\n"
-		"-db \t\tdebug backtracking\n"
-		"-dh \t\tdebug heap\n"
-		"-ds \t\tdebug detstack\n"
-		"-df \t\tdebug final success/failure\n"
-		"-da \t\tdebug all\n"
-		"-dm \t\tdebug memory allocation\n"
-		"-dG \t\tdebug garbage collection\n"
-		"-dd \t\tdetailed debug\n"
-		"-Di \t\tdebug the program using the internal debugger\n"
-#ifdef MR_USE_EXTERNAL_DEBUGGER
-		"-De \t\tdebug the program using the external debugger\n"
-#endif
-		"-sh<n> \t\tallocate n kb for the heap\n"
-		"-sd<n> \t\tallocate n kb for the det stack\n"
-		"-sn<n> \t\tallocate n kb for the nondet stack\n"
-#ifdef MR_USE_TRAIL
-		"-st<n> \t\tallocate n kb for the trail\n"
-#endif
-		"-sl<n> \t\tallocate n kb for the label table\n"
-		"-zh<n> \t\tallocate n kb for the heap redzone\n"
-		"-zd<n> \t\tallocate n kb for the det stack redzone\n"
-		"-zn<n> \t\tallocate n kb for the nondet stack redzone\n"
-#ifdef MR_USE_TRAIL
-		"-zt<n> \t\tallocate n kb for the trail redzone\n"
-#endif
-		"-C<n> \t\tprimary cache size in kbytes\n"
-#ifdef PARALLEL
-		"-P<n> \t\tnumber of processes to use for parallel execution\n"
-		"\t\tapplies only if Mercury is configured with --enable-parallel\n"
-#endif
-		"-r<n> \t\trepeat n times\n"
-		"-w<name> \tcall predicate with given name (default: main/2)\n"
-		);
+	printf("The MERCURY_OPTIONS environment variable"
+		"contains an invalid option.\n"
+		"Please refer to the Mercury users' guide for details.\n");
 	fflush(stdout);
 	exit(1);
 } /* end usage() */
Index: scripts/c2init.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/c2init.in,v
retrieving revision 1.15
diff -u -r1.15 c2init.in
--- c2init.in	1998/05/30 13:34:09	1.15
+++ c2init.in	1998/06/25 06:17:53
@@ -19,6 +19,15 @@
 Name:	c2init - Create Mercury initialization file.
 Usage:	c2init [options] *.c *.init ...
 Options: 
+	-c <n>, --max-calls <n>
+		Break up the initialization into groups of at most <n> function
+		calls.  (Default value of <n> is 40.)
+	-i, --include-initialization-code
+		Always include code that calls the initialization functions
+		of the various modules. With this option, the debugger can use
+		information from any modules that were compiled with execution
+		tracing to do (partial) stack tracing and uplevel printing
+		even in grades in which this not normally possible.
 	-l, --library
 		Don't generate a \`main()' function.
 		Instead, generate a function
@@ -26,18 +35,15 @@
 		(declared in \"init.h\") that can be called from C code.
 		(A more fine-grained interface is also available;
 		see \"init.h\" for details.)
+	-w <label>, --entry-point <label>
+		Set entry point to <label>.
+		(Default value is \`mercury__main_2_0'.)
 	-x, --extra-inits
 		Search \`.c' files for extra initialization functions.
 		(This may be necessary if the C files contain
 		hand-coded C code with \`INIT' comments, rather than
 		containing only C code that was automatically generated
 		by the Mercury compiler.)
-	-c <n>, --max-calls <n>
-		Break up the initialization into groups of at most <n> function
-		calls.  (Default value of <n> is 40.)
-	-w <label>, --entry-point <label>
-		Set entry point to <label>.
-		(Default value is \`mercury__main_2_0'.)
 Environment variables:
 	MERCURY_MOD_LIB_DIR, MERCURY_MOD_LIB_MODS, MERCURY_MKINIT.
 "
@@ -52,18 +58,21 @@
 # maximum number of calls to put in a single function
 maxcalls=40
 defentry=mercury__main_2_0
+init_opt=""
 library_opt=""
 extra_inits_opt=""
 while true; do
 	case "$1" in
 	-c|--max-calls)
 		maxcalls="$2"; shift; shift;;
-	-w|--entry-point)
-		defentry="$2"; shift; shift;;
+	-i|--include-initialization-code)
+		init_opt="-i"; shift;;
 	-l|--library)
 		library_opt="-l"; shift;;
 	-l-|--no-library)
 		library_opt=""; shift;;
+	-w|--entry-point)
+		defentry="$2"; shift; shift;;
 	-x|--extra-inits)
 		extra_inits_opt="-x"; shift;;
 	-x-|--no-extra-inits)
@@ -83,10 +92,10 @@
 done
 
 case $# in
-	0) exec $MKINIT -w"$defentry" -c"$maxcalls" $library_opt \
-		$extra_inits_opt $MERCURY_MOD_LIB_MODS
+	0) exec $MKINIT -c"$maxcalls" $init_opt $library_opt \
+		-w"$defentry" $extra_inits_opt $MERCURY_MOD_LIB_MODS
 	   ;;
-	*) exec $MKINIT -w"$defentry" -c"$maxcalls" $library_opt \
-		$extra_inits_opt "$@" $MERCURY_MOD_LIB_MODS
+	*) exec $MKINIT -c"$maxcalls" $init_opt $library_opt \
+		-w"$defentry" $extra_inits_opt "$@" $MERCURY_MOD_LIB_MODS
 	   ;;
 esac
Index: tests/debugger/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/Mmakefile,v
retrieving revision 1.5
diff -u -r1.5 Mmakefile
--- Mmakefile	1998/05/18 02:05:11	1.5
+++ Mmakefile	1998/06/24 10:45:42
@@ -14,6 +14,7 @@
 	queens
 
 MCFLAGS = --trace all $(EXTRA_MCFLAGS)
+EXTRA_C2INITFLAGS = -i
 
 # Not all grades can be used with stack layouts
 #
Index: tests/debugger/debugger_regs_lib.exp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/debugger_regs_lib.exp,v
retrieving revision 1.1
diff -u -r1.1 debugger_regs_lib.exp
--- debugger_regs_lib.exp	1998/05/16 07:31:04	1.1
+++ debugger_regs_lib.exp	1998/06/25 06:27:19
@@ -2,14 +2,6 @@
 mtrace>        2:      2  2 CALL DET   debugger_regs_lib:data/41-0 
 mtrace>        3:      2  2 EXIT DET   debugger_regs_lib:data/41-0 
 mtrace>           HeadVar__1           		[1, 2, 3, 4, 5]
-          HeadVar__2           		a0
-          HeadVar__3           		a1
-          HeadVar__4           		a2
-          HeadVar__5           		a3
-          HeadVar__6           		a4
-          HeadVar__7           		a5
-          HeadVar__8           		a6
-          HeadVar__9           		a7
           HeadVar__10          		a8
           HeadVar__11          		a9
           HeadVar__12          		b0
@@ -20,6 +12,7 @@
           HeadVar__17          		b5
           HeadVar__18          		b6
           HeadVar__19          		b7
+          HeadVar__2           		a0
           HeadVar__20          		b8
           HeadVar__21          		b9
           HeadVar__22          		c0
@@ -30,6 +23,7 @@
           HeadVar__27          		c5
           HeadVar__28          		c6
           HeadVar__29          		c7
+          HeadVar__3           		a1
           HeadVar__30          		c8
           HeadVar__31          		c9
           HeadVar__32          		d0
@@ -40,8 +34,14 @@
           HeadVar__37          		d5
           HeadVar__38          		d6
           HeadVar__39          		d7
+          HeadVar__4           		a2
           HeadVar__40          		d8
           HeadVar__41          		d9
+          HeadVar__5           		a3
+          HeadVar__6           		a4
+          HeadVar__7           		a5
+          HeadVar__8           		a6
+          HeadVar__9           		a7
 mtrace> a0a1a2a3a4a5a6a7a8a9
 b0b1b2b3b4b5b6b7b8b9
 c0c1c2c3c4c5c6c7c8c9
Index: tests/debugger/debugger_regs_lib.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/debugger_regs_lib.inp,v
retrieving revision 1.1
diff -u -r1.1 debugger_regs_lib.inp
--- debugger_regs_lib.inp	1998/05/16 07:31:08	1.1
+++ debugger_regs_lib.inp	1998/06/25 06:26:14
@@ -1,4 +1,4 @@
 
 
-p
+p *
 c
Index: tests/debugger/interpreter_lib.exp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/interpreter_lib.exp,v
retrieving revision 1.1
diff -u -r1.1 interpreter_lib.exp
--- interpreter_lib.exp	1998/05/16 07:31:15	1.1
+++ interpreter_lib.exp	1998/06/25 06:37:34
@@ -9,23 +9,36 @@
 F:			finish this call, printing the trace.
 <N> g:			go to event #N, not printing the trace.
 <N> G:			go to event #N, printing the trace.
-p:			print the variables live at this point.
+v:			list the names of the variables live at this point.
+l <n>:			set ancestor level to <n>
+p <n>:			print variable #n (or all vars if <n> is '*')
 r:			continue until forward execution is resumed.
 [<N>] [s]:		skip N events, not printing the trace (default: N=1).
 [<N>] S:		skip N events, printing the trace (default: N=1).
 ?:			list all the breakpoints.
 + <N>:			enable breakpoint #N.
 - <N>:			disable breakpoint #N.
-mtrace> mtrace> Pure Prolog Interpreter.
+mtrace> Pure Prolog Interpreter.
 
 Consulting file `interpreter_lib.m'...
-      45:     20  4 CALL DET   interpreter_lib:consult_until_eof/4-0 
-mtrace>           HeadVar__1           		[]
-          HeadVar__3           		state('<<c_pointer>>')
-mtrace>       47:     22  6 CALL DET   parser:read_term/3-0 
+      46:     21  5 CALL DET   term_io:read_term/3-0 
+mtrace>         0 HeadVar__2
 mtrace>           HeadVar__2           		state('<<c_pointer>>')
-mtrace>    13300:     22  6 EXIT DET   parser:read_term/3-0 
-mtrace>           HeadVar__1           		term(varset(0, empty, empty), functor(atom(":-"), [functor(atom("module"), [functor(atom("interpreter"), [], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22)))
-          HeadVar__3           		state('<<c_pointer>>')
-mtrace>  0: + interpreter_lib:consult_until_eof
-mtrace> mtrace> ?- 
\ No newline at end of file
+mtrace>  0: + interpreter_lib:database_assert_clause
+mtrace>    13446:   5011  6 CALL DET   interpreter_lib:database_assert_clause/4-0 
+mtrace>           HeadVar__1           		[]
+          HeadVar__2           		varset(0, empty, empty)
+          HeadVar__3           		functor(atom(":-"), [functor(atom("module"), [functor(atom("interpreter_lib"), [], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22))
+mtrace>    13447:   5011  6 ELSE DET   interpreter_lib:database_assert_clause/4-0 e;
+   13448:   5012  7 CALL DET   term:context_init/1-0 
+   13449:   5012  7 EXIT DET   term:context_init/1-0 
+   13450:   5011  6 EXIT DET   interpreter_lib:database_assert_clause/4-0 
+mtrace>           HeadVar__1           		[]
+          HeadVar__2           		varset(0, empty, empty)
+          HeadVar__3           		functor(atom(":-"), [functor(atom("module"), [functor(atom("interpreter_lib"), [], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22))
+          HeadVar__4           		[clause(varset(0, empty, empty), functor(atom(":-"), [functor(atom("module"), [functor(atom("interpreter_lib"), [], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22))], context("interpreter_lib.m", 22)), functor(atom("true"), [], context("", 0)))]
+mtrace>    13451:   5013  6 CALL DET   interpreter_lib:consult_until_eof/4-0 
+mtrace>   368828:   5013  6 EXIT DET   interpreter_lib:consult_until_eof/4-0 
+mtrace>   368829:   5010  5 EXIT DET   interpreter_lib:consult_until_eof_2/5-0 
+mtrace>   368830:     20  4 EXIT DET   interpreter_lib:consult_until_eof/4-0 
+mtrace> ?- 
\ No newline at end of file
Index: tests/debugger/interpreter_lib.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/interpreter_lib.inp,v
retrieving revision 1.1
diff -u -r1.1 interpreter_lib.inp
--- interpreter_lib.inp	1998/05/16 07:31:19	1.1
+++ interpreter_lib.inp	1998/06/25 06:36:12
@@ -1,11 +1,14 @@
 h
-b interpreter_lib consult_until_eof
+45s
+v
+p *
+b interpreter_lib database_assert_clause
 c
-p
-2s
-p
+p *
+F
+p *
+
 f
-p
-?
-- 0
+
+
 c
Index: tests/debugger/queens_lib.exp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/queens_lib.exp,v
retrieving revision 1.1
diff -u -r1.1 queens_lib.exp
--- queens_lib.exp	1998/05/16 07:31:26	1.1
+++ queens_lib.exp	1998/06/25 06:27:48
@@ -1,7 +1,7 @@
        1:      1  1 CALL CCMUL queens_lib:main/2-0 
 mtrace>           HeadVar__1           		state('<<c_pointer>>')
 mtrace>        2:      2  2 CALL DET   queens_lib:data/1-0 
-mtrace> mtrace: no live variables
+mtrace> mtrace: there are no live variables
 mtrace>        3:      2  2 EXIT DET   queens_lib:data/1-0 
 mtrace>           HeadVar__1           		[1, 2, 3, 4, 5]
 mtrace>        4:      3  2 CALL NON   queens_lib:queen/2-0 
@@ -14,12 +14,17 @@
 mtrace>           HeadVar__2           		[1, 2, 3, 4, 5]
 mtrace>        8:      5  4 DISJ NON   queens_lib:qdelete/3-0 c2;d1;
 mtrace>           HeadVar__2           		[1, 2, 3, 4, 5]
-          V_11                 		1
           V_10                 		[2, 3, 4, 5]
+          V_11                 		1
+mtrace> Ancestor level set to 1
+mtrace>           HeadVar__1           		[1, 2, 3, 4, 5]
+mtrace> Ancestor level set to 2
+mtrace>         0 HeadVar__1
+mtrace>           HeadVar__1           		[1, 2, 3, 4, 5]
 mtrace>        9:      5  4 EXIT NON   queens_lib:qdelete/3-0 
 mtrace>           HeadVar__1           		1
-          HeadVar__3           		[2, 3, 4, 5]
           HeadVar__2           		[1, 2, 3, 4, 5]
+          HeadVar__3           		[2, 3, 4, 5]
 mtrace>       10:      6  4 CALL NON   queens_lib:qperm/2-0 
 mtrace>           HeadVar__1           		[2, 3, 4, 5]
 mtrace>       11:      6  4 SWTC NON   queens_lib:qperm/2-0 s1;
@@ -28,12 +33,12 @@
 mtrace>           HeadVar__2           		[2, 3, 4, 5]
 mtrace>       13:      7  5 DISJ NON   queens_lib:qdelete/3-0 c2;d1;
 mtrace>           HeadVar__2           		[2, 3, 4, 5]
-          V_11                 		2
           V_10                 		[3, 4, 5]
+          V_11                 		2
 mtrace>       14:      7  5 EXIT NON   queens_lib:qdelete/3-0 
 mtrace>           HeadVar__1           		2
-          HeadVar__3           		[3, 4, 5]
           HeadVar__2           		[2, 3, 4, 5]
+          HeadVar__3           		[3, 4, 5]
 mtrace>       15:      8  5 CALL NON   queens_lib:qperm/2-0 
 mtrace>           HeadVar__1           		[3, 4, 5]
 mtrace>       16:      8  5 SWTC NON   queens_lib:qperm/2-0 s1;
@@ -42,12 +47,12 @@
 mtrace>           HeadVar__2           		[3, 4, 5]
 mtrace>       18:      9  6 DISJ NON   queens_lib:qdelete/3-0 c2;d1;
 mtrace>           HeadVar__2           		[3, 4, 5]
-          V_11                 		3
           V_10                 		[4, 5]
+          V_11                 		3
 mtrace>       19:      9  6 EXIT NON   queens_lib:qdelete/3-0 
 mtrace>           HeadVar__1           		3
-          HeadVar__3           		[4, 5]
           HeadVar__2           		[3, 4, 5]
+          HeadVar__3           		[4, 5]
 mtrace>       20:     10  6 CALL NON   queens_lib:qperm/2-0 
 mtrace>           HeadVar__1           		[4, 5]
 mtrace>       21:     10  6 SWTC NON   queens_lib:qperm/2-0 s1;
@@ -56,12 +61,12 @@
 mtrace>           HeadVar__2           		[4, 5]
 mtrace>       23:     11  7 DISJ NON   queens_lib:qdelete/3-0 c2;d1;
 mtrace>           HeadVar__2           		[4, 5]
-          V_11                 		4
           V_10                 		[5]
+          V_11                 		4
 mtrace>       24:     11  7 EXIT NON   queens_lib:qdelete/3-0 
 mtrace>           HeadVar__1           		4
-          HeadVar__3           		[5]
           HeadVar__2           		[4, 5]
+          HeadVar__3           		[5]
 mtrace>       25:     12  7 CALL NON   queens_lib:qperm/2-0 
 mtrace>           HeadVar__1           		[5]
 mtrace>       26:     12  7 SWTC NON   queens_lib:qperm/2-0 s1;
@@ -70,33 +75,33 @@
 mtrace>           HeadVar__2           		[5]
 mtrace>       28:     13  8 DISJ NON   queens_lib:qdelete/3-0 c2;d1;
 mtrace>           HeadVar__2           		[5]
-          V_11                 		5
           V_10                 		[]
+          V_11                 		5
 mtrace>       29:     13  8 EXIT NON   queens_lib:qdelete/3-0 
 mtrace>           HeadVar__1           		5
-          HeadVar__3           		[]
           HeadVar__2           		[5]
+          HeadVar__3           		[]
 mtrace>       30:     14  8 CALL NON   queens_lib:qperm/2-0 
 mtrace>           HeadVar__1           		[]
 mtrace>       31:     14  8 SWTC NON   queens_lib:qperm/2-0 s2;
 mtrace> mtrace>       32:     14  8 EXIT NON   queens_lib:qperm/2-0 
-mtrace>           HeadVar__2           		[]
-          HeadVar__1           		[]
+mtrace>           HeadVar__1           		[]
+          HeadVar__2           		[]
 mtrace>       33:     12  7 EXIT NON   queens_lib:qperm/2-0 
-mtrace>           HeadVar__2           		[5]
-          HeadVar__1           		[5]
+mtrace>           HeadVar__1           		[5]
+          HeadVar__2           		[5]
 mtrace>       34:     10  6 EXIT NON   queens_lib:qperm/2-0 
-mtrace>           HeadVar__2           		[4, 5]
-          HeadVar__1           		[4, 5]
+mtrace>           HeadVar__1           		[4, 5]
+          HeadVar__2           		[4, 5]
 mtrace>       35:      8  5 EXIT NON   queens_lib:qperm/2-0 
-mtrace>           HeadVar__2           		[3, 4, 5]
-          HeadVar__1           		[3, 4, 5]
+mtrace>           HeadVar__1           		[3, 4, 5]
+          HeadVar__2           		[3, 4, 5]
 mtrace>       36:      6  4 EXIT NON   queens_lib:qperm/2-0 
-mtrace>           HeadVar__2           		[2, 3, 4, 5]
-          HeadVar__1           		[2, 3, 4, 5]
+mtrace>           HeadVar__1           		[2, 3, 4, 5]
+          HeadVar__2           		[2, 3, 4, 5]
 mtrace>       37:      4  3 EXIT NON   queens_lib:qperm/2-0 
-mtrace>           HeadVar__2           		[1, 2, 3, 4, 5]
-          HeadVar__1           		[1, 2, 3, 4, 5]
+mtrace>           HeadVar__1           		[1, 2, 3, 4, 5]
+          HeadVar__2           		[1, 2, 3, 4, 5]
 mtrace>       38:     15  3 CALL SEMI  queens_lib:safe/1-0 
 mtrace>           HeadVar__1           		[1, 2, 3, 4, 5]
 mtrace>       39:     15  3 SWTC SEMI  queens_lib:safe/1-0 s1;
Index: util/mkinit.c
===================================================================
RCS file: /home/mercury1/repository/mercury/util/mkinit.c,v
retrieving revision 1.33
diff -u -r1.33 mkinit.c
--- mkinit.c	1998/06/08 08:29:17	1.33
+++ mkinit.c	1998/06/25 06:15:01
@@ -43,6 +43,7 @@
 static char **files;
 static bool output_main_func = TRUE;
 static bool c_files_contain_extra_inits = FALSE;
+static bool need_initialization_code = FALSE;
 
 static int num_modules = 0;
 static int num_errors = 0;
@@ -178,6 +179,12 @@
 	"}\n"
 	;
 
+
+static const char if_need_to_init[] = 
+	"#if defined(MR_NEED_INITIALIZATION_CODE)\n\n"
+	;
+
+
 /* --- function prototypes --- */
 static	void parse_options(int argc, char *argv[]);
 static	void usage(void);
@@ -249,21 +256,25 @@
 parse_options(int argc, char *argv[])
 {
 	int	c;
-	while ((c = getopt(argc, argv, "c:w:lx")) != EOF) {
+	while ((c = getopt(argc, argv, "c:ilw:x")) != EOF) {
 		switch (c) {
 		case 'c':
 			if (sscanf(optarg, "%d", &maxcalls) != 1)
 				usage();
 			break;
 
-		case 'w':
-			entry_point = optarg;
+		case 'i':
+			need_initialization_code = TRUE;
 			break;
 
 		case 'l':
 			output_main_func = FALSE;
 			break;
 
+		case 'w':
+			entry_point = optarg;
+			break;
+
 		case 'x':
 			c_files_contain_extra_inits = TRUE;
 			break;
@@ -309,6 +320,10 @@
 {
 	int filenum;
 
+	if (! need_initialization_code) {
+		fputs(if_need_to_init, stdout);
+	}
+
 	fputs("static void init_modules_0(void)\n", stdout);
 	fputs("{\n", stdout);
 
@@ -316,7 +331,10 @@
 		process_file(files[filenum]);
 	}
 
-	fputs("}\n\n", stdout);
+	fputs("}\n", stdout);
+	if (! need_initialization_code) {
+		fputs("\n#endif\n\n", stdout);
+	}
 }
 
 static void 
@@ -327,8 +345,16 @@
 	fputs("static void init_modules(void)\n", stdout);
 	fputs("{\n", stdout);
 
+	if (! need_initialization_code) {
+		fputs(if_need_to_init, stdout);
+	}
+
 	for (i = 0; i <= num_modules; i++) {
 		printf("\tinit_modules_%d();\n", i);
+	}
+
+	if (! need_initialization_code) {
+		fputs("\n#endif\n", stdout);
 	}
 
 	fputs("}\n", stdout);

New File: runtime/mercury_trace_permanent.c
===================================================================
/*
** Copyright (C) 1997-1998 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/

/*
** mercury_trace_permanent.c implements the interface between the main part
** of the runtime system (mainly mercury_wrapper.c) and the part of the
** tracing subsystem that has to be present even if no module in the program
** is compiled with execution tracing.
** are in mercury_trace_util.c.
**
** Main author: Zoltan Somogyi.
*/

#include "mercury_imp.h"
#include "mercury_trace.h"
#include "mercury_trace_util.h"
#include "mercury_trace_internal.h"
#include "mercury_trace_external.h"
#include "mercury_engine.h"
#include "mercury_wrapper.h"
#include "mercury_misc.h"
#include <stdio.h>
#include <unistd.h>		/* for the write system call */

/*
** Do we want to use the debugger within this process, or do want to use
** the Opium-style trace analyzer debugger implemented by an external process.
** This variable is set in mercury_wrapper.c and never modified afterwards.
*/

MR_trace_type	MR_trace_handler = MR_TRACE_INTERNAL;

/*
** Compiler generated tracing code will check whether MR_trace_enabled is true,
** before calling MR_trace. For now, and until we implement interface tracing,
** MR_trace_enabled should keep the same value throughout the execution of
** the entire program after being set in mercury_wrapper.c. There is one
** exception to this: the Mercury routines called as part of the functionality
** of the tracer itself (e.g. the term browser) should always be executed
** with MR_trace_enabled set to FALSE.
*/

bool		MR_trace_enabled = FALSE;

/*
** MR_trace_call_seqno counts distinct calls. The prologue of every
** procedure assigns the current value of this counter as the sequence number
** of that invocation and increments the counter. This is the only way that
** MR_trace_call_seqno is modified.
**
** MR_trace_call_depth records the current depth of the call tree. The prologue
** of every procedure assigns the current value of this variable plus one
** as the depth of that invocation. Just before making a call, the caller
** will set MR_trace_call_depth to its own remembered depth value. 
** These are the only ways in which MR_trace_call_depth is modified.
**
** Although neither MR_trace_call_seqno nor MR_trace_call_depth are used
** directly in this module, the seqno and depth arguments of MR_trace
** always derive their values from the saved values of these two global
** variables.
*/

Unsigned	MR_trace_call_seqno = 0;
Unsigned	MR_trace_call_depth = 0;

/*
** MR_trace_event_number is a simple counter of events. This is used in
** two places: here, for display to the user and for skipping a given number
** of events, and when printing an abort message, so that the programmer
** can zero in on the source of the problem more quickly.
*/

Unsigned	MR_trace_event_number = 0;

/*
** MR_trace_from_full is a boolean that is set before every call;
** it states whether the caller is being fully traced, or only interface
** traced. If the called code is interface traced, it will generate
** call, exit and fail trace events only if MR_trace_from_full is true.
** (It will never generate internal events.) If the called code is fully
** traced, it will always generate all trace events, external and internal,
** regardless of the setting of this variable on entry.
**
** The initial value is set to TRUE to allow the programmer to gain
** control in the debugger when main/2 is called.
*/

Bool		MR_trace_from_full = 1;

void
MR_trace_init(void)
{
#ifdef MR_USE_EXTERNAL_DEBUGGER
	if (MR_trace_handler == MR_TRACE_EXTERNAL)
		MR_trace_init_external(); /* should be in this module */
#endif
}

void
MR_trace_final(void)
{
#ifdef MR_USE_EXTERNAL_DEBUGGER
	if (MR_trace_handler == MR_TRACE_EXTERNAL)
		MR_trace_final_external(); /* should be in this module */
#endif
}

void
MR_trace_start(bool enabled)
{
	MR_trace_event_number = 0;
	MR_trace_call_seqno = 0;
	MR_trace_call_depth = 0;
	MR_trace_from_full = TRUE;
	MR_trace_enabled = enabled;
}

void
MR_trace_end(void)
{
	MR_trace_enabled = FALSE;
}

void
MR_trace_report(FILE *fp)
{
	if (MR_trace_event_number > 0) {
		/*
		** This means that the executable was compiled with tracing,
		** which implies that the user wants trace info on abort.
		*/

		fprintf(fp, "Last trace event was event #%ld.\n",
			(long) MR_trace_event_number);
	}
}

void
MR_trace_report_raw(int fd)
{
	char	buf[80];	/* that ought to be more than long enough */

	if (MR_trace_event_number > 0) {
		/*
		** This means that the executable was compiled with tracing,
		** which implies that the user wants trace info on abort.
		*/

		sprintf(buf, "Last trace event was event #%ld.\n",
			(long) MR_trace_event_number);
		write(fd, buf, strlen(buf));
	}
}

New File: runtime/mercury_trace_permanent.h
===================================================================
/*
** Copyright (C) 1997-1998 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/

/*
** mercury_trace_permanent.h defines the interface between the main part
** of the runtime system (mainly mercury_wrapper.c) and the part of the
** tracing subsystem that has to be present even if no module in the program
** is compiled with execution tracing.
*/

#ifndef MERCURY_TRACE_PERMANENT_H
#define MERCURY_TRACE_PERMANENT_H

/*
** MR_trace_init() is called from mercury_runtime_init()
** when the debuggee programs begins, to perform any initialization
** that must be done before any traced Mercury code is executed.
** This includes the initialization code written in Mercury as well as main.
**
** MR_trace_start(enabled) is called from mercury_runtime_init()
** after the initialization code written in Mercury is executed,
** when we are about to start executing main. The argument says
** whether tracing is enabled for main (it is never enabled for
** initialization and finalization routines).
**
** MR_trace_end() is called from mercury_runtime_terminate() just
** after main has terminated and just before we call the finalization
** code written in Mercury.
**
** MR_trace_final() is called from mercury_runtime_terminate()
** after all Mercury code, including finalization code, has terminated.
*/

extern	void	MR_trace_init(void);
extern	void	MR_trace_start(bool enabled);
extern	void	MR_trace_end(void);
extern	void	MR_trace_final(void);

#define	MR_trace_incr_seq()	(++MR_trace_call_seqno)
#define	MR_trace_incr_depth()	(++MR_trace_call_depth)
#define	MR_trace_reset_depth(d)	do { MR_trace_call_depth = (d); } while (0)

/*
** The globals that define the interface between the tracing subsystem
** and compiled code, and which must be initialized in the permanent part
** of the runtime.
*/

extern	Word		MR_trace_call_seqno;
extern	Word		MR_trace_call_depth;

typedef enum {
	MR_TRACE_INTERNAL,
	MR_TRACE_EXTERNAL
} MR_trace_type;

extern	MR_trace_type	MR_trace_handler;
extern	bool		MR_trace_enabled;

extern	Unsigned	MR_trace_event_number;
extern	Bool		MR_trace_from_full;

/*
** These functions will report the number of the last event,
** if there have been some events, and will do nothing otherwise.
*/

extern	void	MR_trace_report(FILE *fp);
extern	void	MR_trace_report_raw(int fd);

#endif /* MERCURY_TRACE_PERMANENT_H */




More information about the developers mailing list