Files
mercury/runtime/mercury_trace_base.h
Zoltan Somogyi a83aad6681 Remove references to nondet foreign_proc from the definition of the data
Estimated hours taken: 2
Branches: main

Remove references to nondet foreign_proc from the definition of the data
structures that define stack layouts.

runtime/mercury_stack_layout.h:
	Remove the trace ports that could occur in nondet foreign_procs
	from the definition of the trace port type used in C code.

mdbcomp/prim_data.m:
	Remove the trace ports that could occur in nondet foreign_procs
	from the definition of the trace port type used in Mercury code.

compiler/layout_out.m:
compiler/stack_layout.m:
compiler/trace_params.m:
mdbcomp/trace_counts.m:
runtime/mercury_trace_base.h:
trace/mercury_trace_declarative.h:
	Delete references to those ports.

runtime/mercury_stack_layout.h:
	Update the binary compatibility version number for debuggable
	executables, since the port number of user events has changed.
2011-09-26 04:30:48 +00:00

779 lines
31 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1997-2009, 2011 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** mercury_trace_base.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 tracing is not enabled.
** The part of the tracing system that required only when tracing is enabled
** is in the trace directory.
*/
#ifndef MERCURY_TRACE_BASE_H
#define MERCURY_TRACE_BASE_H
#include "mercury_engine.h" /* for MR_MAXFLAG */
#include "mercury_stack_layout.h"
#include "mercury_std.h"
#include "mercury_tabling.h" /* for MR_TableNode */
#include "mercury_goto.h" /* for MR_declare_entry */
#include <stdio.h> /* for FILE; should be after mercury headers */
/*
** This enum should EXACTLY match
** - the macro `MR_TRACE_PORT_ACTUAL_NAMES' below,
** - the macro `MR_TRACE_PORT_SIMPLIFIED_NAMES' below,
** - the type `trace_port' in mdbcomp/prim_data.m,
** - the predicate `trace_port_to_string' in compiler/layout_out.m, and
** - the function `port_number' in compiler/trace_params.m.
*/
typedef enum {
MR_PORT_CALL,
MR_PORT_EXIT,
MR_PORT_REDO,
MR_PORT_FAIL,
MR_PORT_TAILREC_CALL,
MR_PORT_EXCEPTION,
MR_PORT_COND,
MR_PORT_THEN,
MR_PORT_ELSE,
MR_PORT_NEG_ENTER,
MR_PORT_NEG_SUCCESS, /* negated goal failed; negation succeeds */
MR_PORT_NEG_FAILURE, /* negated goal succeeded; negation fails */
MR_PORT_DISJ_FIRST,
MR_PORT_DISJ_LATER,
MR_PORT_SWITCH,
MR_PORT_USER,
MR_PORT_NONE
} MR_TracePort;
#define MR_PORT_NUM_PORTS ((int) MR_PORT_NONE + 1)
#define MR_TRACE_PORT_ACTUAL_NAMES \
"CALL", \
"EXIT", \
"REDO", \
"FAIL", \
"TAIL", \
"EXCP", \
"COND", \
"THEN", \
"ELSE", \
"NEGE", \
"NEGS", \
"NEGF", \
"DSJF", \
"DSJL", \
"SWTC", \
"USER", \
"NONE"
#define MR_TRACE_PORT_SIMPLIFIED_NAMES \
"CALL", \
"EXIT", \
"REDO", \
"FAIL", \
"TAIL", \
"EXCP", \
"COND", \
"THEN", \
"ELSE", \
"NEGE", \
"NEGS", \
"NEGF", \
"DISJ", \
"DISJ", \
"SWTC", \
"USER", \
"NONE"
extern const char *MR_actual_port_names[];
extern const char *MR_simplified_port_names[];
/*
** The following array says if a label inside a procedure is
** uniquely identifiable by its goal path only, its port only or
** whether both the port and goal path are necessary.
*/
typedef enum {
PATH_ONLY, PORT_ONLY, PORT_AND_PATH
} MR_PathPort;
extern MR_PathPort MR_named_count_port[MR_PORT_NUM_PORTS];
extern void MR_trace_name_count_port_ensure_init(void);
#define MR_trace_incr_seq() ((MR_Word) ++MR_trace_call_seqno)
#define MR_trace_incr_depth() ((MR_Word) ++MR_trace_call_depth)
#define MR_trace_fill_std_slots(s1, s2, s3) \
(((s1) = MR_trace_event_number), \
((s2) = MR_trace_incr_seq()), \
((s3) = MR_trace_incr_depth()))
#define MR_trace_tailrec_std_slots(s1, s2, s3) \
(((s1) = MR_trace_event_number), \
((s2) = MR_trace_incr_seq()), \
((s3) = (s3) + 1))
#define MR_trace_reset_depth(d) \
(MR_trace_call_depth = (MR_Unsigned) (d))
#define MR_trace_reset_depth_from_full(d) \
((MR_trace_call_depth = (MR_Unsigned) (d)), \
(MR_trace_from_full = MR_TRUE))
#define MR_trace_reset_depth_from_shallow(d) \
((MR_trace_call_depth = (MR_Unsigned) (d)), \
(MR_trace_from_full = MR_FALSE))
/*
** MR_trace is called from Mercury modules compiled with tracing.
** If the event is supposed to be traced, it performs an indirect call
** through MR_trace_func_ptr, which will point either to MR_trace_real,
** which is defined in the trace library, or to MR_trace_fake, defined here,
** which just prints an error message and aborts, or to MR_trace_count, also
** defined here, which counts the execution of the event.
**
** The return value, if not NULL, says where execution should continue
** after the event. (NULL means it should continue as usual.)
*/
extern MR_Code *MR_trace(const MR_LabelLayout *);
extern MR_Code *MR_trace_fake(const MR_LabelLayout *);
extern MR_Code *MR_trace_count(const MR_LabelLayout *);
extern MR_Code *MR_user_trace(const MR_LabelLayout *);
/*
** These three variables implement a table of module layout structures,
** sorted on module name, maintained by the macros in mercury_array_macros.h.
**
** Insertions are handled by MR_insert_module_info_into_module_table.
*/
extern const MR_ModuleLayout **MR_module_infos;
extern unsigned MR_module_info_next;
extern unsigned MR_module_info_max;
extern void MR_insert_module_info_into_module_table(
const MR_ModuleLayout *module_layout);
/*
** For every label reachable from the module table, write the id of the label
** and the number of times it has been executed to the specified file. For
** labels that haven't been executed, write them out only if the coverage_test
** argument is true. The return value is the number of labels whose trace count
** information was actually written out.
**
** The file can be recognized as a Mercury trace counts file as its first
** line matches MR_TRACE_COUNT_FILE_ID. The value of that macro should be
** kept in sync with trace_count_file_id in mdbcomp/trace_counts.m.
** One of the later lines gives the name of the program that the trace counts
** were derived from; this should be supplied by the caller as the progname
** argument.
*/
#define MR_TRACE_COUNT_FILE_ID "Mercury trace counts file\n"
extern unsigned int MR_trace_write_label_exec_counts(FILE *fp,
const char *progname,
MR_bool coverage_test);
/*
** Figure out where (to which file) to write out the label execution counts,
** and then invoke MR_trace_write_label_exec_counts to write it out there.
** If the user has asked for this data to be summarized, do that too.
**
** The dummy argument allows this function to be registered with
** MR_register_exception_cleanup.
*/
extern void MR_trace_record_label_exec_counts(void *dummy);
/*
** 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(MR_bool enabled);
extern void MR_trace_end(void);
extern void MR_trace_final(void);
/*
** Kill any windows created by mdb.
*/
extern void (*MR_trace_shutdown)(void);
/*
** 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.
**
** XXX They should probably be in MercuryEngine.
*/
/*
** MR_debug_enabled says whether debugging of the program is enabled.
** It should keep the same value throughout the execution of the entire
** program after being set in mercury_wrapper.c, with two exceptions.
** First, the Mercury routines called as part of the functionality
** of the tracer itself (e.g. the term browser) should always be executed
** with MR_debug_enabled set to MR_FALSE. Second, when a procedure has
** the tabled_for_io_unitize annotation, which means that it can both do I/O
** and call Mercury code, then we turn the procedure and its descendants
** into a single unit by turning off tracing within the descendants.
** This is required to prevent the I/O tabling problems that could otherwise
** arise if we got retries from within the descendants.
*/
extern MR_bool MR_debug_enabled;
/*
** MR_debug_ever_enabled will keep the same value throughout the execution of
** the entire program after being set in mercury_wrapper.c to the same value
** as MR_debug_enabled. Unlike MR_debug_enabled, it is never reset, so one can
** use its value to test whether tracing was ever enabled.
*/
extern MR_bool MR_debug_ever_enabled;
/*
** When writing out trace counts at the end of execution, we will write out
** the identities of labels with zero execution counts if and only if
** MR_coverage_test_enabled is true.
*/
extern MR_bool MR_coverage_test_enabled;
/*
** If MR_trace_count_summary_file is not NULL, then its value gives the
** name of the file in which to accumulate trace count information. If this
** file doesn't exist, the trace counts data will be printed to it. If this
** file does exist, the trace counts data will be printed to files with this
** name as a base name plus a suffix .1, .2, .3 etc until the number reaches
** MR_trace_count_summary_max, at which point the program will invoke
** the command named by MR_trace_count_summary_cmd to consolidate all those
** trace counts in one file (the one named by MR_trace_count_summary_file).
*/
extern const char *MR_trace_count_summary_file;
extern const char *MR_trace_count_summary_cmd;
extern unsigned int MR_trace_count_summary_max;
/*
** MR_trace_count_enabled will keep the same value throughout the execution of
** the entire program after being set in mercury_wrapper.c to the same value
** as MR_debug_enabled. Unlike MR_debug_enabled, it is never reset, so one can
** use its value to test whether tracing was ever enabled.
*/
extern MR_bool MR_trace_count_enabled;
/*
** MR_trace_counts_file records the filename to use when dumping trace counts.
** It may be NULL, in which case a unique file name will be generated.
*/
extern char *MR_trace_counts_file;
/*
** MR_trace checks whether MR_trace_func_enabled is true, and return
** immediately if it is not.
**
** MR_trace_func_enabled should be updated whenever either of the variables
** it depends on is updated. The reason why we require this is that
** MR_trace_func_enabled is read many times, but MR_debug_enabled and
** MR_trace_count_enabled are updated only infrequently.
**
** Usually, MR_trace_func_enabled should be updated with the macro below.
** However, MR_debug_enabled and MR_trace_count_enabled can never be set
** simultaneously, and in places where performance is important, the update
** of MR_trace_func_enabled can exploit this.
*/
extern MR_bool MR_trace_func_enabled;
#define MR_update_trace_func_enabled() \
do { \
MR_trace_func_enabled = \
MR_debug_enabled || MR_trace_count_enabled; \
} while (0)
/*
** MR_selected_trace_func_ptr contains the address of the function to call
** in MR_trace if MR_trace_func_enabled is true.
**
** Since it is set from a signal handler (MR_trace_interrupt_handler),
** it must be declared `volatile'.
*/
extern MR_Code *(*volatile MR_selected_trace_func_ptr)(
const MR_LabelLayout *);
/*
** 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 and retry are the only
** ways 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 and retry 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.
*/
extern MR_Unsigned MR_trace_call_seqno;
extern MR_Unsigned MR_trace_call_depth;
/*
** MR_trace_event_number is a simple counter of events. This is used in
** two places: in the debugger 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.
*/
extern MR_Unsigned MR_trace_event_number;
/*
** MR_trace_from_full is a boolean that is set before every call;
** it states whether the caller is being deep traced, or only shallow
** traced. If the called code is shallow traced, it will generate
** interface trace events only if MR_trace_from_full is true.
** (It will never generate internal events.) If the called code is deep
** 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 MR_TRUE to allow the programmer to gain
** control in the debugger when main/2 is called.
*/
extern MR_bool MR_trace_from_full;
/*
** If set to true, MR_standardize_event_details modifies how functions that
** print event numbers and call sequence numbers operate, making them
** standardize these numbers. The Nth event number to be printed will be
** printed as E<N> and the Nth call sequence number will be printed as C<N>
** regardless of their actual values. This is intended to avoid hardcoding
** concrete event and call numbers in the expected outputs of the debugger
** test cases.
**
** The functions MR_standardize_event_num and MR_standardize_call_num implement
** the standardization itself.
*/
extern MR_bool MR_standardize_event_details;
extern MR_Unsigned MR_standardize_event_num(MR_Unsigned event_num);
extern MR_Unsigned MR_standardize_call_num(MR_Unsigned call_num);
/*
** 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.
*/
typedef enum {
MR_TRACE_INTERNAL,
#ifdef MR_USE_EXTERNAL_DEBUGGER
MR_TRACE_EXTERNAL
#endif
} MR_Trace_Type;
extern MR_Trace_Type MR_trace_handler;
/*
** MR_trace_unhide_events is a boolean. Normally, it is set to false, which
** means that events that the compiler designates as hidden are really hidden
** from the procedural debugger, being visible only when building the annotated
** trace. When an mdb command intended for implementors only sets it to true,
** hidden events will be visible to the procedural debugger too, i.e. the
** hidden annotation on events will cease to be effective.
**
** The MR_trace_have_unhid_events is a boolean that is set to true whenever
** MR_trace_unhide_events is set to true, and it is never reset to false.
** MR_trace_have_unhid_events will therefore be true if the user has ever
** unhidden events. The declarative debugger checks this flag and refuses
** to perform if it is set, because if this flag has ever been set, then the
** numbering of events may not be the same after a retry, which makes it
** impossible to *reliably* find the event at which the "dd" command was issued
** while building the annotated trace.
*/
extern MR_bool MR_trace_unhide_events;
extern MR_bool MR_trace_have_unhid_events;
/*
** When executing a retry on a call that has reused the stack frame of some
** of its ancestors, we start executing the code of the procedure from the very
** beginning. This code sets the stack slot that contains the count of
** how many times that stack frame was reused to zero. This is the right thing
** to do for normal execution, but doing it after a retry screws up the
** debugger's picture of the stack.
**
** These two variables are part of the fix for this problem. The boolean
** MR_trace_tailrec_have_reused_frames is almost always false. However,
** when we are executing a retry of a procedure with TAIL events, we set it
** momentarily to true, and set MR_trace_tailrec_num_reused_frames to the
** original value of the frame reuse counter. We make the procedure prologue
** for procedures with TAIL events check MR_trace_tailrec_have_reused_frames,
** and it is set, we initialize the slot not to zero but to the value in
** MR_trace_tailrec_num_reused_frames (we also reset the boolean to false).
**
** Note that the contents of MR_trace_tailrec_num_reused_frames are valid
** only when MR_trace_tailrec_have_reused_frames is true.
*/
extern MR_bool MR_trace_tailrec_have_reused_frames;
extern MR_Unsigned MR_trace_tailrec_num_reused_frames;
/*
** The details of I/O tabling are documented in library/table_builtin.m.
*/
typedef enum {
/* from program start to first debugger event */
MR_IO_TABLING_UNINIT,
/* from first debugger event to "table_io start" command */
MR_IO_TABLING_BEFORE,
/* from "table_io start" command to "table_io end" command */
MR_IO_TABLING_DURING,
/* from "table_io end" command to program exit */
MR_IO_TABLING_AFTER
} MR_IoTablingPhase;
typedef MR_Unsigned MR_IoActionNum;
#define MR_IO_ACTION_MAX ((MR_IoActionNum) -1)
extern MR_IoTablingPhase MR_io_tabling_phase;
/* True iff I/O tabling is enabled. */
extern MR_bool MR_io_tabling_enabled;
/* The root of the trie that we use for tabling I/O. */
extern MR_TableNode MR_io_tabling_pointer;
/* The I/O action number of the last I/O action. */
extern MR_IoActionNum MR_io_tabling_counter;
/* The highest I/O action number ever reached ("hwm" = "high water mark"). */
extern MR_IoActionNum MR_io_tabling_counter_hwm;
/* The highest I/O action number which is too early to be tabled. */
extern MR_IoActionNum MR_io_tabling_start;
/* The highest I/O action number which is to be tabled. */
extern MR_IoActionNum MR_io_tabling_end;
/* The event number at which I/O tabling was started; zero before start. */
extern MR_Unsigned MR_io_tabling_start_event_num;
/* The event number at which I/O tabling was stopped; zero before stop. */
extern MR_Unsigned MR_io_tabling_stop_event_num;
/* The flag that controls whether we should generate diagnostics. */
extern MR_bool MR_io_tabling_debug;
/* The flag that controls whether I/O tabling is allowed at all. */
extern MR_bool MR_io_tabling_allowed;
/*
** 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);
/*
** If MR_trace_report_msg is not NULL, it will be included in messages
** from MR_trace_report.
*/
extern char *MR_trace_report_msg;
/*
** This function prints an error message and aborts. It should be
** called in situations where tracing is required, but `--trace' was
** not passed to c2init.
*/
extern void MR_tracing_not_enabled(void);
/*
** Return the details of I/O action <action_number> in three pieces:
** the name of the I/O action procedure in *proc_name_ptr, a boolean that is
** true iff procedure is a function in *is_func_ptr, and a Mercury
** representation of the argument list (minus the IO state arguments)
** in *arg_list_ptr.
** This function uses the heap pointer, so calls to it must be wrapped
** with MR_save_transient_hp() and MR_restore_transient_hp().
**
** This function is called from the Mercury code in the debugger, in the
** browser directory. It is here, not in the trace directory, because code
** in the browser directory cannot call functions in the trace directory.
**
** If the io action, action_number, has not been tabled, then this
** function will return MR_FALSE, otherwise it will return MR_TRUE.
*/
extern MR_bool MR_trace_get_action(MR_IoActionNum action_number,
MR_ConstString *proc_name_ptr, MR_Word *is_func_ptr,
MR_Word *arg_list_ptr);
/*
** MR_turn_off_debug saves the current values of the variables controlling
** debugging (execution tracing and diagnostics) in the structure provided by
** the caller, and then turns them off. MR_turn_debug_back_on restores the
** saved values from the structure. If include_counter_vars is set, they also
** save and restore the global variables containing the event and sequence
** number counters and the call depth.
*/
typedef struct {
MR_bool MR_sds_debug_enabled;
MR_bool MR_sds_io_tabling_enabled;
MR_bool MR_sds_debugflags[MR_MAXFLAG];
MR_bool MR_sds_include_counter_vars;
MR_Unsigned MR_sds_trace_call_seqno;
MR_Unsigned MR_sds_trace_call_depth;
MR_Unsigned MR_sds_trace_event_number;
} MR_SavedDebugState;
extern void MR_turn_off_debug(MR_SavedDebugState *saved_state,
MR_bool include_counter_vars);
extern void MR_turn_debug_back_on(
const MR_SavedDebugState *saved_state);
/*
** These functions allow library/exceptions.m to tell the debuggers
** which exception has been thrown.
*/
extern void MR_trace_set_exception_value(MR_Word exception);
extern MR_Word MR_trace_get_exception_value(void);
/*
** Return a pointer to the execution count of a particular label.
*/
extern MR_Unsigned *MR_trace_lookup_trace_count(
const MR_LabelLayout *label_layout);
/*
** If MR_TRACE_HISTOGRAM is defined, MR_trace maintains two arrays of integers,
** MR_trace_histogram_all and MR_trace_histogram_exp, in which the element
** with subscript d is incremented when a trace event occurs at depth d.
** The intention is that the MR_trace_histogram_all records all events
** and is never reset, which means that it records information about a whole
** execution of the program. MR_trace_histogram_exp on the other hand can be
** zeroed by a command from the debugger at e.g a call port, and examined at
** e.g. an exit port, which means that it can record information about the
** execution of a call.
**
** Both arrays are allocated via malloc, and resized on demand. They are
** always the same size, and this size is stored in MR_trace_histogram_max.
** MR_trace_histogram_hwm stores the high water mark, i.e. the biggest
** depth number that has been encountered so far in the execution of the
** program.
*/
#ifdef MR_TRACE_HISTOGRAM
extern int *MR_trace_histogram_all;
extern int *MR_trace_histogram_exp;
extern int MR_trace_histogram_max;
extern int MR_trace_histogram_hwm;
extern void MR_trace_print_histogram(FILE *fp, const char *which,
int *histogram, int max);
#endif /* MR_TRACE_HISTOGRAM */
extern void MR_io_tabling_stats(FILE *fp);
/*
** These two functions work on a table that maps proc layout structures
** to the Mercury terms representing the bodies of those procedures.
** The Mercury term representation of the procedure body is constructed
** on demand from the bytecode in the procedure layout structure, but since
** this construction process allocates a significant amount of memory and
** takes a nontrivial amount of time, we cache the results in this table.
**
** MR_insert_proc_defn_rep adds the result of a conversion to the cache.
**
** MR_lookup_proc_defn_rep checks whether a previous call to
** MR_insert_proc_defn_rep has already cached the procedure body
** representation of a given procedure; a zero return value means that
** the answer is "no".
*/
extern void MR_insert_proc_defn_rep(const MR_ProcLayout *proc_layout,
MR_Word proc_defn_rep);
extern MR_Word MR_lookup_proc_defn_rep(const MR_ProcLayout *proc_layout);
#ifndef MR_HIGHLEVEL_CODE
MR_declare_entry(MR_do_trace_redo_fail_shallow);
MR_declare_entry(MR_do_trace_redo_fail_deep);
#endif /* !MR_HIGHLEVEL_CODE */
/*
** The compiler emits the following macro at each system-defined trace event.
*/
#define MR_EVENT_SYS \
{ \
MR_Code *MR_jumpaddr; \
MR_save_transient_registers(); \
MR_jumpaddr = MR_trace((const MR_LabelLayout *) \
MR_HASH_DEF_LABEL_LAYOUT); \
MR_restore_transient_registers(); \
if (MR_jumpaddr != NULL) MR_GOTO(MR_jumpaddr); \
}
/*
** The compiler emits the following macro at each user-defined trace event.
*/
#define MR_EVENT_USER \
{ \
MR_Code *MR_jumpaddr; \
MR_save_transient_registers(); \
MR_jumpaddr = MR_user_trace((const MR_LabelLayout *) \
MR_HASH_DEF_LABEL_LAYOUT); \
MR_restore_transient_registers(); \
if (MR_jumpaddr != NULL) MR_GOTO(MR_jumpaddr); \
}
/*
** The compiler used to emit the following macros instead of those above.
*/
#define MR_EVENT(label_layout) \
{ \
MR_Code *MR_jumpaddr; \
MR_save_transient_registers(); \
MR_jumpaddr = MR_trace((const MR_LabelLayout *) \
&MR_LABEL_LAYOUT_NAME(MR_add_prefix(label))); \
MR_restore_transient_registers(); \
if (MR_jumpaddr != NULL) MR_GOTO(MR_jumpaddr); \
}
#define MR_USER_EVENT(label_layout) \
{ \
MR_Code *MR_jumpaddr; \
MR_save_transient_registers(); \
MR_jumpaddr = MR_user_trace((const MR_LabelLayout *) \
&MR_LABEL_LAYOUT_NAME(MR_add_prefix(label))); \
MR_restore_transient_registers(); \
if (MR_jumpaddr != NULL) MR_GOTO(MR_jumpaddr); \
}
/*
** When using the heap pointer, we need to restore it, in case it is
** transient.
*/
#define MR_TRACE_USE_HP(STATEMENTS) \
do { \
MR_restore_transient_registers(); \
STATEMENTS; \
MR_save_transient_registers(); \
} while (0)
/*
** When calling Mercury code defined using `pragma export', we need
** to call save_registers() and restore_registers() around it.
** That in turn needs to be preceded/followed by
** restore/save_transient_registers() if it is in a C function.
**
** We also need to ensure that Mercury code called from the debugger
** doesn't screw up the data structures belonging to the program being
** debugged.
**
** XXX The code here is very similar to MR_turn_off_debug/MR_turn_debug_back_on
** in the source file. Look into merging the two pieces of code.
*/
#if defined(MR_DEEP_PROFILING) && defined(MR_EXEC_TRACE)
#define MR_TRACE_CALL_MERCURY_DEEP_BEGIN \
do { \
MR_disable_deep_profiling_in_debugger = MR_TRUE; \
} while (0)
#define MR_TRACE_CALL_MERCURY_DEEP_END \
do { \
MR_disable_deep_profiling_in_debugger = MR_FALSE; \
} while (0)
#else
#define MR_TRACE_CALL_MERCURY_DEEP_BEGIN ((void) 0)
#define MR_TRACE_CALL_MERCURY_DEEP_END ((void) 0)
#endif
#define MR_TRACE_CALL_MERCURY(STATEMENTS) \
do { \
MR_bool saved_debug_enabled; \
MR_bool saved_io_enabled; \
MR_Unsigned saved_trace_call_seqno; \
MR_Unsigned saved_trace_call_depth; \
MR_Unsigned saved_trace_event_number; \
\
MR_TRACE_CALL_MERCURY_DEEP_BEGIN; \
saved_debug_enabled = MR_debug_enabled; \
saved_io_enabled = MR_io_tabling_enabled; \
saved_trace_call_seqno = MR_trace_call_seqno; \
saved_trace_call_depth = MR_trace_call_depth; \
saved_trace_event_number = MR_trace_event_number; \
MR_debug_enabled = MR_FALSE; \
MR_update_trace_func_enabled(); \
MR_io_tabling_enabled = MR_FALSE; \
MR_restore_transient_registers(); \
MR_save_registers(); \
STATEMENTS; \
MR_restore_registers(); \
MR_save_transient_registers(); \
MR_debug_enabled = saved_debug_enabled; \
MR_update_trace_func_enabled(); \
MR_io_tabling_enabled = saved_io_enabled; \
MR_trace_call_seqno = saved_trace_call_seqno; \
MR_trace_call_depth = saved_trace_call_depth; \
MR_trace_event_number = saved_trace_event_number; \
MR_TRACE_CALL_MERCURY_DEEP_END; \
} while (0)
#endif /* MERCURY_TRACE_BASE_H */