Files
mercury/runtime/mercury_stack_layout.h
Zoltan Somogyi c733b0359b Give the Mercury debugger the ability to detect cliques of mutually recursive
Estimated hours taken: 30
Branches: main

Give the Mercury debugger the ability to detect cliques of mutually recursive
predicates on the stack. Exploit this ability to enhance the debugger's
level, retry, finish and stack commands.

runtime/mercury_stack_trace.[ch]:
	Add a function, MR_find_clique_entry, that detects the clique
	that contains the top stack frame. This is used to implement the new
	arguments "clentry" and "clparent" (short for clique entry and parent)
	options of the level, retry and finish commands. "clique" is a synonym
	for "clentry" in these commands.

	Add a function, MR_dump_stack_layout_clique, that implements the
	new capabilities of the stack command. It can detect more than one
	clique, anywhere on the stack.

	To make this possible, modify the existing functions for printing
	the lines of stack traces. These used to keep some information around
	between calls in global variables. Now that information is stored in
	two structures that the caller passes them. One contains the parameters
	that govern what is to be printed, the other contains information about
	what has been buffered up to be printed, but has not been flushed yet.
	(The old code was confused in its handling of parameters. Some parts
	of it looked up the global variables storing them, while other parts
	were given the parameter values by their callers, values that could
	have been -but weren't- inconsistent.)

	Change the buffer flushing code to be idempotent, since in the new
	code, sometimes it is hard to avoid flushing the buffer more than once,
	and we want only the first to print its contents.

	Make some type names conform to our standard style.

runtime/mercury_stack_layout.h:
	Add a new flag in MR_ProcLayouts: a flag that indicates that the
	procedure has one or more higher order arguments. The new code in
	mercury_stack_trace.c handles procedures with this flag specially:
	it does not consider two non-consecutive occurrences of such procedures
	on the stack to be necessarily part of the same clique. This is to
	avoid having two calls to e.g. list.map in different part of the
	program pulling all the procedures between those parts on the stack
	into a single clique. (The deep profiler has a very similar tweak.)

	Add a pointer to the corresponding part of the compiler.

compiler/hlds_pred.m:
	Add a predicate to test whether a predicate has any higher order args.

compiler/stack_layout.m:
	When computing the flag in proc layouts, call the new procedure in
	hlds_pred.m to help figure it out.

trace/mercury_trace_cmd_backward.c:
	Implement the new options of the "retry" command.

trace/mercury_trace_cmd_forward.c:
	Implement the new options of the "finish" command.

trace/mercury_trace_cmd_browsing.c:
	Implement the "new options of the "level" command.

	Implement the new functionality of the "stack" command.

trace/mercury_trace_util.[ch]:
	Add some code common to the implementations of the level, retry and
	finish commands.

trace/mercury_trace_external.c:
	Conform to the changes to the runtime.

doc/user_guide.texi:
	Document the debugger's new capabilities.

NEWS:
	Announce the debugger's new capabilities.

tests/debugger/mutrec.{m,inp,exp}:
	A new test case to test the handling of the stack command
	in the presence of cliques.

tests/debugger/mutrec_higher_order.{m,inp,exp}:
	A new test case to test the handling of the stack command
	in the presence of cliques and higher order predicates.

tests/debugger/Mmakefile:
	Enable both new test cases.
2012-06-05 18:19:33 +00:00

1522 lines
74 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1998-2012 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 MERCURY_STACK_LAYOUT_H
#define MERCURY_STACK_LAYOUT_H
/*
** mercury_stack_layout.h -
**
** Definitions for stack layout data structures. These are generated by the
** compiler, and are used by the parts of the runtime system that need to look
** at the stacks (and sometimes the registers) and make sense of their
** contents. The parts of the runtime system that need to do this include
** exception handling, the debugger, and (eventually) the accurate garbage
** collector.
**
** For a general description of the idea of stack layouts, see the paper
** "Run time type information in Mercury" by Tyson Dowd, Zoltan Somogyi,
** Fergus Henderson, Thomas Conway and David Jeffery, which is available from
** the Mercury web site. The relevant section is section 3.8, but be warned:
** while the general principles remain applicable, the details have changed
** since that paper was written.
**
** NOTE: The constants and data-structures used here need to be kept in
** sync with the ones generated in the compiler. If you change anything here,
** you may need to change stack_layout.m, layout.m, and/or layout_out.m in
** the compiler directory as well.
*/
#include "mercury_types.h"
#include "mercury_std.h" /* for MR_VARIABLE_SIZED */
#include "mercury_tags.h"
#include "mercury_type_info.h" /* for MR_PseudoTypeInfo */
#include "mercury_proc_id.h" /* for MR_ProcId */
#include "mercury_goto.h" /* for MR_PROC_LAYOUT etc */
#include "mercury_tabling.h" /* for MR_TableTrieStep etc */
#include "mercury_bootstrap.h" /* for MR_Table_Trie_Step */
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_Determinism.
*/
/*
** The max_soln component of the determinism is encoded in the 1 and 2 bits.
** The can_fail component of the determinism is encoded in the 4 bit.
** The first_solution component of the determinism is encoded in the 8 bit.
**
** MR_DETISM_AT_MOST_MANY could also be defined as ((d) & 3) == 3),
** but this would be less efficient, since the C compiler does not know
** that we do not set the 1 bit unless we also set the 2 bit.
**
** NOTE: this must match the encoding specified by represent_determinism/1
** in mdbcomp/program_representation.m.
*/
typedef MR_int_least16_t MR_Determinism;
#define MR_DETISM_DET 6
#define MR_DETISM_SEMI 2
#define MR_DETISM_NON 3
#define MR_DETISM_MULTI 7
#define MR_DETISM_ERRONEOUS 4
#define MR_DETISM_FAILURE 0
#define MR_DETISM_CCNON 10
#define MR_DETISM_CCMULTI 14
#define MR_DETISM_MAX 14
#define MR_DETISM_AT_MOST_ZERO(d) (((d) & 3) == 0)
#define MR_DETISM_AT_MOST_ONE(d) (((d) & 3) == 2)
#define MR_DETISM_AT_MOST_MANY(d) (((d) & 1) != 0)
#define MR_DETISM_CAN_FAIL(d) (((d) & 4) == 0)
#define MR_DETISM_FIRST_SOLN(d) (((d) & 8) != 0)
#define MR_DETISM_DET_STACK(d) (!MR_DETISM_AT_MOST_MANY(d) \
|| MR_DETISM_FIRST_SOLN(d))
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_LongLval and MR_ShortLval.
*/
/*
** MR_LongLval is an MR_Unsigned which describes a location.
** This includes lvals such as stack slots, general registers, and special
** registers such as succip, hp, etc, as well as locations whose address is
** given as a typeinfo inside the type class info structure pointed to by an
** lval.
**
** What kind of location an MR_LongLval refers to is encoded using
** a low tag with MR_LONG_LVAL_TAGBITS bits; the type MR_LongLvalType
** describes the different tag values. The interpretation of the rest of
** the word depends on the location type:
**
** Locn Rest
**
** MR_r(Num) Num (register number)
** MR_f(Num) Num (register number)
** MR_stackvar(Num) Num (stack slot number)
** MR_framevar(Num) Num (stack slot number)
** MR_succip
** MR_maxfr
** MR_curfr
** MR_hp
** MR_sp
** constant See below
** indirect(Base, N) See below
** unknown (The location is not known)
**
** For constants, the rest of the word is a pointer to static data. The
** pointer has only two low tag bits free, so we reserve every four-bit tag
** which has 00 as its bottom two bits for representing them.
**
** For indirect references, the word exclusive of the tag consists of
** (a) an integer with MR_LONG_LVAL_OFFSETBITS bits giving the index of
** the typeinfo inside a type class info (to be interpreted by
** MR_typeclass_info_type_info or the predicate
** private_builtin.type_info_from_typeclass_info, which calls it) and
** (b) a MR_LongLval value giving the location of the pointer to the
** type class info. This MR_LongLval value will *not* have an indirect tag.
**
** This data is generated in stack_layout.represent_locn_as_int,
** which must be kept in sync with the constants and macros defined here.
*/
typedef MR_Unsigned MR_LongLval;
typedef enum {
MR_LONG_LVAL_TYPE_CONS_0 = 0,
MR_LONG_LVAL_TYPE_R = 1,
MR_LONG_LVAL_TYPE_F = 2,
MR_LONG_LVAL_TYPE_STACKVAR = 3,
MR_LONG_LVAL_TYPE_CONS_1 = 4,
MR_LONG_LVAL_TYPE_FRAMEVAR = 5,
MR_LONG_LVAL_TYPE_SUCCIP = 6,
MR_LONG_LVAL_TYPE_MAXFR = 7,
MR_LONG_LVAL_TYPE_CONS_2 = 8,
MR_LONG_LVAL_TYPE_CURFR = 9,
MR_LONG_LVAL_TYPE_HP = 10,
MR_LONG_LVAL_TYPE_SP = 11,
MR_LONG_LVAL_TYPE_CONS_3 = 12,
MR_LONG_LVAL_TYPE_DOUBLE_STACKVAR = 13,
MR_LONG_LVAL_TYPE_DOUBLE_FRAMEVAR = 14,
MR_LONG_LVAL_TYPE_INDIRECT = 15,
MR_LONG_LVAL_TYPE_CONS_4 = 16,
MR_LONG_LVAL_TYPE_UNKNOWN = 17,
MR_LONG_LVAL_TYPE_CONS_5 = 20,
MR_LONG_LVAL_TYPE_CONS_6 = 24,
MR_LONG_LVAL_TYPE_CONS_7 = 28
} MR_LongLvalType;
/* This must be in sync with stack_layout.long_lval_tag_bits */
#define MR_LONG_LVAL_TAGBITS 5
#define MR_LONG_LVAL_CONST_TAGBITS 2
#define MR_LONG_LVAL_TYPE(Locn) \
((MR_LongLvalType) ((Locn) & ((1 << MR_LONG_LVAL_TAGBITS) - 1)))
#define MR_LONG_LVAL_NUMBER(Locn) \
((int) ((Locn) >> MR_LONG_LVAL_TAGBITS))
#define MR_LONG_LVAL_CONST(Locn) \
(* (MR_Word *) ((Locn) & ~ ((1 << MR_LONG_LVAL_CONST_TAGBITS) - 1)))
/* This must be in sync with stack_layout.offset_bits */
#define MR_LONG_LVAL_OFFSETBITS 6
#define MR_LONG_LVAL_INDIRECT_OFFSET(LocnNumber) \
((int) ((LocnNumber) & ((1 << MR_LONG_LVAL_OFFSETBITS) - 1)))
#define MR_LONG_LVAL_INDIRECT_BASE_LVAL_INT(LocnNumber) \
(((MR_uint_least32_t) (LocnNumber)) >> MR_LONG_LVAL_OFFSETBITS)
#define MR_LONG_LVAL_STACKVAR_INT(n) \
(((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_STACKVAR)
#define MR_LONG_LVAL_FRAMEVAR_INT(n) \
(((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_FRAMEVAR)
#define MR_LONG_LVAL_R_REG_INT(n) \
(((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_R)
/*
** MR_ShortLval is a MR_uint_least8_t which describes an location. This
** includes lvals such as stack slots and general registers that have small
** numbers, and special registers such as succip, hp, etc.
**
** What kind of location an MR_LongLval refers to is encoded using
** a low tag with 2 bits; the type MR_ShortLval_Type describes
** the different tag values. The interpretation of the rest of the word
** depends on the location type:
**
** Locn Tag Rest
** MR_r(Num) 0 Num (register number)
** MR_stackvar(Num) 1 Num (stack slot number)
** MR_framevar(Num) 2 Num (stack slot number)
** special reg 3 MR_LongLvalType
**
** This data is generated in stack_layout.represent_locn_as_byte,
** which must be kept in sync with the constants and macros defined here.
*/
typedef MR_uint_least8_t MR_ShortLval;
typedef enum {
MR_SHORT_LVAL_TYPE_R,
MR_SHORT_LVAL_TYPE_STACKVAR,
MR_SHORT_LVAL_TYPE_FRAMEVAR,
MR_SHORT_LVAL_TYPE_SPECIAL
} MR_ShortLval_Type;
/* This must be in sync with stack_layout.short_lval_tag_bits */
#define MR_SHORT_LVAL_TAGBITS 2
#define MR_SHORT_LVAL_TYPE(Locn) \
((MR_ShortLval_Type) \
(((MR_Word) Locn) & ((1 << MR_SHORT_LVAL_TAGBITS) - 1)))
#define MR_SHORT_LVAL_NUMBER(Locn) \
((int) (((MR_Word) Locn) >> MR_SHORT_LVAL_TAGBITS))
#define MR_SHORT_LVAL_STACKVAR(n) \
((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS) \
+ MR_SHORT_LVAL_TYPE_STACKVAR))
#define MR_SHORT_LVAL_FRAMEVAR(n) \
((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS) \
+ MR_SHORT_LVAL_TYPE_FRAMEVAR))
#define MR_SHORT_LVAL_R_REG(n) \
((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS) \
+ MR_SHORT_LVAL_TYPE_R))
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_UserEvent and MR_UserEventSpec.
*/
/*
** Our layout structures link to information about user events from two places:
** the label layout structures of labels that correspond to user events,
** and the module layout structures of modules that contain user events.
** Label layout structures link to MR_UserEvent structures; module layout
** structures link to MR_UserEventSpec structures. Most of the information
** is in the MR_UserEventSpec structures; MR_UserEvent structures contain
** only information that may differ between two instances of the same event.
*/
/*
** The fields of MR_UserEvent:
**
** The event_number field contains the ordinal number of the event in the
** event set the module was compiled with: it gives the identity of the event.
** (Event numbers start at zero.) This field is also the link to the rest of
** the information about the event, contained in the MR_UserEventSpec structure
** linked to by the module layout structure. The MR_user_event_spec macro
** follows this link.
**
** The next two fields all point to arrays whose length is the number of
** attributes (which is available in the MR_UserEventSpec structure).
**
** attr_locns[i] gives the location where we can find the value of the
** i'th attribute (the first attribute is attribute zero). This is
** meaningful only if the attribute is not a synthesized attribute.
**
** attr_var_nums[i] gives the variable number of the i'th attribute;
** if it contains zero, that means the attribute is synthesized. This field
** is used by the debugger to display the associated value just once
** (not twice, as both attribute and variable value) with "print *". (Note
** that we don't delete the variables that are also attributes from the set of
** live variables in layout structures, because that would require any native
** garbage collector to look at the list of attributes as well as the list of
** other variables, slowing it down.)
*/
typedef MR_uint_least16_t MR_HLDSVarNum;
struct MR_UserEvent_Struct {
MR_uint_least16_t MR_ue_event_number;
MR_LongLval *MR_ue_attr_locns;
const MR_HLDSVarNum *MR_ue_attr_var_nums;
};
/*
** The fields of MR_UserEventSpec:
**
** The event_name field contains the name of the event.
**
** The num_attrs field gives the number of attributes.
**
** The next three fields (attr_names, attr_types and synth_attrs) all point
** to arrays whose length is the number of attributes.
**
** attr_names[i] gives the name of the i'th attribute.
**
** attr_types[i] is the typeinfo giving the type of the i'th attribute.
**
** If the i'th attribute is synthesized, synth_attrs[i] points to the
** information required to synthesize it: the number of the attribute
** containing the synthesis function, the number of arguments of the synthesis
** function, and an array of attribute numbers (of length num_arg_attrs)
** giving the list of those arguments. The depend_attrs field will point to
** a list of numbers of the synthesized attributes whose values must be
** materialized before this attribute can be evaluated. (This list will include
** the argument attributes, and will be in a feasible evaluation order.)
** If the i'th attribute is not synthesized, synth_attrs[i] and depend_attrs[i]
** will both be NULL. (For now, depend_attrs[i] will not be filled in for
** synthesized attributes either.)
**
** The synth_attr_order field points to an array of attribute numbers that
** gives the order in which the values of the synthesized attributes should be
** evaluated. The array is ended by -1 as a sentinel.
**
** The synth_attrs and synth_attr_order fields will both be NULL for events
** that have no synthesized attributes.
*/
struct MR_SynthAttr_Struct {
MR_int_least16_t MR_sa_func_attr;
MR_int_least16_t MR_sa_num_arg_attrs;
MR_uint_least16_t *MR_sa_arg_attrs;
MR_int_least16_t *MR_sa_depend_attrs;
};
struct MR_UserEventSpec_Struct {
const char *MR_ues_event_name;
MR_uint_least16_t MR_ues_num_attrs;
const char **MR_ues_attr_names;
MR_TypeInfo *MR_ues_attr_types;
MR_SynthAttr *MR_ues_synth_attrs;
MR_int_least16_t *MR_ues_synth_attr_order;
};
#define MR_user_event_spec(label_layout) \
label_layout->MR_sll_entry->MR_sle_module_layout-> \
MR_ml_user_event_specs[label_layout->MR_sll_user_event-> \
MR_ue_event_number]
#define MR_user_event_set_name(label_layout) \
label_layout->MR_sll_entry->MR_sle_module_layout-> \
MR_ml_user_event_set_name
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_LabelLayout.
*/
/*
** An MR_LabelLayout structure describes the debugging and accurate gc
** information available at a given label.
**
** The MR_sll_entry field points to the proc layout structure of the procedure
** in which the label occurs.
**
** The MR_sll_port field will contain a negative number if there is no
** execution tracing port associated with the label. If there is, the
** field will contain a value of type MR_TracePort. For labels associated
** with events, this will be the port of the event. For return labels,
** this port will be exception (since exception events are associated with
** the return from the call that raised the exception).
**
** The MR_sll_hidden field contains a boolean which is meaningful only if the
** label corresponds to an execution tracing event. It will be MR_HIDDEN if the
** event should have no effects that the user can see (no message printed, no
** increment of the event number etc), and MR_NOT_HIDDEN otherwise. Hidden
** events are sometimes needed by the declarative debugger to provide the
** proper context for other events.
**
** The MR_sll_goal_path field contains an offset into the module-wide string
** table, leading to a string that gives the goal path associated with the
** label. If there is no meaningful goal path associated with the label,
** the offset will be zero, leading to the empty string. You can use the macro
** MR_label_goal_path to convert the value in the MR_sll_goal_path field to a
** string.
**
** A possible alternative would be to represent goal paths using statically
** allocated terms of the reverse_goal_path type. An almost-complete diff
** making that change was posted to the mercury-reviews mailing list on
** 30 Sep 2011, but it was not committed, since it lead to a 4% *increase*
** in the size of asm_fast.gc.debug executables. Even though different goal
** paths share a tail (the part of the path near the root) with the
** static reverse_goal_path term representation but not with the string
** representation, the string representation is so much more compact
** (usually taking 4 to 6 bytes for most steps) than the Mercury term
** representation (1 to 4 words for a step, plus 2 words for the rgp_cons,
** totalling at least 24 bytes per step on 64 bit systems), that the string
** representation is significantly more compact overall. The Mercury term
** representation does have the potential to speed up the implementation of
** the operations in the declarative debugger that need to test whether
** two goal paths represent two different direct components of the same parent
** goal. If the two different goal paths are represented as reverse_goal_paths,
** then doing this test on RGPA and RGPB simply requires the test
**
** RGPA = rgp_cons(ParentRGPA, StepA),
** RGPB = rgp_cons(ParentRGPB, StepB),
** ParentRGPA = ParentRGPB
**
** and the last step can be done by a pointer comparison. This test can be done
** in constant time, whereas the current implementation of the same test
** (the function MR_trace_same_construct in trace/mercury_trace_declarative.c)
** works in linear time.
**
** If the label is the label of a user-defined event, then the
** MR_sll_user_event field will point to information about the user event;
** otherwise, the field will be NULL.
**
** The remaining fields give information about the values live at the given
** label, if this information is available. If it is available, the
** MR_has_valid_var_count macro will return true and the fields after the count
** are meaningful; if it is not available, the macro will return false and
** those fields are not meaningful (i.e. you are looking at an
** MR_LabelLayoutNoVarInfo structure).
**
** The format in which we store information about the values live at the label
** is somewhat complicated, due to our desire to make this information compact.
** We can represent a location in one of two ways, as an 8-bit MR_ShortLval
** or as a 32-bit MR_LongLval. We prefer representing a location as an
** MR_ShortLval, but of course not all locations can be represented in
** this way, so those other locations are represented as MR_LongLvals.
**
** The MR_sll_var_count field, if it is valid, is encoded by the formula
** (#Long << MR_SHORT_COUNT_BITS + #Short), where #Short is the number
** data items whose descriptions fit into an MR_ShortLval and #Long is the
** number of data items whose descriptions do not. (The number of distinct
** values that fit into 8 bits also fits into 8 bits, but since some
** locations hold the value of more than one variable at a time, not all
** the values need to be distinct; this is why MR_SHORT_COUNT_BITS is
** more than 8.)
**
** The MR_sll_types field points to an array of #Long + #Short
** MR_PseudoTypeInfos each giving the type of a live data item, with
** a small integer instead of a pointer representing a special kind of
** live data item (e.g. a saved succip or hp). This field will be null if
** #Long + #Short is zero.
**
** The MR_sll_long_locns field points to an array of #Long MR_LongLvals,
** while the MR_sll_short_locns field points to an array of #Short
** MR_ShortLvals. The element at index i in the MR_sll_long_locns vector
** will have its type described by the element at index i in the MR_sll_types
** vector, while the element at index i in the MR_sll_short_locns vector
** will have its type described by the element at index #Long + i in the
** MR_sll_types vector. MR_sll_long_locns will be NULL if #Long is zero,
** and similarly MR_sll_short_locns will be NULL if #Short is zero.
**
** The MR_sll_var_nums field may be NULL, which means that there is no
** information about the variable numbers of the live values. If the field
** is not NULL, it points to a vector of variable numbers, which has an element
** for each live data item. This is either the live data item's HLDS variable
** number, or one of two special values. Zero means that the live data item
** is not a variable (e.g. it is a saved copy of succip). The largest possible
** 16-bit number on the other hand means "the number of this variable does not
** fit into 16 bits". With the exception of these special values, the value
** in this slot uniquely identifies the live data item. (Not being able to
** uniquely identify nonvariable data items is never a problem. Not being able
** to uniquely identify variables is a problem, at the moment, only to the
** extent that the debugger cannot print their names.)
**
** The types of the live variables may or may not have type variables in them.
** If they do not, the MR_sll_tvars field will be NULL. If they do, it will
** point to an MR_TypeParamLocns structure that gives the locations of the
** typeinfos for those type variables. This structure gives the number of type
** variables and their locations, so that the code that needs the type
** parameters can materialize all the type parameters from their location
** descriptions in one go. This is an optimization, since the type parameter
** vector could simply be indexed on demand by the type variable's variable
** number stored within the MR_PseudoTypeInfos stored inside the vector
** pointed to by the MR_sll_types field.
**
** Since we allocate type variable numbers sequentially, the MR_tp_param_locns
** vector will usually be dense. However, after all variables whose types
** include e.g. type variable 2 have gone out of scope, variables whose
** types include type variable 3 may still be around. In cases like this,
** the entry for type variable 2 will be zero; this signals to the code
** in the internal debugger that materializes typeinfo structures that
** this typeinfo structure need not be materialized. Note that the array
** element MR_tp_param_locns[i] describes the location of the typeinfo
** structure for type variable i+1, since array offsets start at zero
** but type variable numbers start at one.
**
** The MR_sll_label_num_in_module is used for counting the number of times
** the event of this label is executed. It gives the label's index in the
** array pointed to by the module layout's MR_ml_label_exec_count field;
** whenever the event of this label is executed, the element in that array
** indicated by this index will be incremented (when MR_trace_count_enabled
** is set). The array element at index zero is ignored. A label layout will
** have zero in its MR_sll_label_num_in_module field if the label doesn't
** correspond to an event.
**
** XXX: Presently, inst information is ignored; we assume that all live values
** are ground.
*/
#define MR_HIDDEN 1
#define MR_NOT_HIDDEN 0
struct MR_TypeParamLocns_Struct {
MR_uint_least32_t MR_tp_param_count;
MR_LongLval MR_tp_param_locns[MR_VARIABLE_SIZED];
};
struct MR_LabelLayout_Struct {
const MR_ProcLayout *MR_sll_entry;
MR_int_least8_t MR_sll_port;
MR_int_least8_t MR_sll_hidden;
MR_uint_least16_t MR_sll_label_num_in_module;
MR_uint_least32_t MR_sll_goal_path;
const MR_UserEvent *MR_sll_user_event;
MR_Integer MR_sll_var_count; /* >= 0, encoding Long > 0 */
const MR_TypeParamLocns *MR_sll_tvars;
const MR_PseudoTypeInfo *MR_sll_types;
const MR_HLDSVarNum *MR_sll_var_nums;
const MR_ShortLval *MR_sll_short_locns;
const MR_LongLval *MR_sll_long_locns;
};
typedef struct MR_LabelLayoutShort_Struct {
const MR_ProcLayout *MR_sll_entry;
MR_int_least8_t MR_sll_port;
MR_int_least8_t MR_sll_hidden;
MR_uint_least16_t MR_sll_label_num_in_module;
MR_uint_least32_t MR_sll_goal_path;
const MR_UserEvent *MR_sll_user_event;
MR_Integer MR_sll_var_count; /* >= 0 , encoding Long == 0*/
const MR_TypeParamLocns *MR_sll_tvars;
const MR_PseudoTypeInfo *MR_sll_types;
const MR_HLDSVarNum *MR_sll_var_nums;
const MR_ShortLval *MR_sll_short_locns;
} MR_LabelLayoutShort;
typedef struct MR_LabelLayoutNoVarInfo_Struct {
const MR_ProcLayout *MR_sll_entry;
MR_int_least8_t MR_sll_port;
MR_int_least8_t MR_sll_hidden;
MR_uint_least16_t MR_sll_label_num_in_module;
MR_uint_least32_t MR_sll_goal_path;
const MR_UserEvent *MR_sll_user_event;
MR_Integer MR_sll_var_count; /* < 0 */
} MR_LabelLayoutNoVarInfo;
#define MR_label_goal_path(layout) \
((MR_PROC_LAYOUT_HAS_EXEC_TRACE((layout)->MR_sll_entry)) ? \
((layout)->MR_sll_entry->MR_sle_module_layout \
->MR_ml_string_table \
+ ((layout)->MR_sll_goal_path >> 1)) \
: "")
#define MR_SHORT_COUNT_BITS 10
#define MR_SHORT_COUNT_MASK ((1 << MR_SHORT_COUNT_BITS) - 1)
#define MR_has_valid_var_count(sll) \
(((sll)->MR_sll_var_count) >= 0)
#define MR_has_valid_var_info(sll) \
(((sll)->MR_sll_var_count) > 0)
#define MR_short_desc_var_count(sll) \
(((sll)->MR_sll_var_count) & MR_SHORT_COUNT_MASK)
#define MR_long_desc_var_count(sll) \
(((sll)->MR_sll_var_count) >> MR_SHORT_COUNT_BITS)
#define MR_all_desc_var_count(sll) \
(MR_long_desc_var_count(sll) + MR_short_desc_var_count(sll))
#define MR_var_pti(sll, i) \
((sll)->MR_sll_types[(i)])
#define MR_short_desc_var_locn(sll, i) \
((sll)->MR_sll_short_locns[(i)])
#define MR_long_desc_var_locn(sll, i) \
((sll)->MR_sll_long_locns[(i)])
/*
** Define a stack layout for an internal label.
**
** The only useful information in the structures created by this macro
** is the reference to the procedure layout, which allows you to find the
** stack frame size and the succip location, thereby enabling stack tracing.
**
** For the native garbage collector, we will need to add meaningful
** live value information as well to these macros.
*/
#define MR_LAYOUT_FROM_LABEL(label) \
MR_PASTE2(mercury_data__label_layout__, label)
#define MR_LABEL_LAYOUT_REF(label) \
((const MR_LabelLayout *) &MR_LAYOUT_FROM_LABEL(MR_add_prefix(label)))
#define MR_MAKE_USER_INTERNAL_LAYOUT(module, name, arity, mode, label) \
MR_LabelLayoutNoVarInfo \
MR_label_layout_user_name(module, name, arity, mode, label) = { \
(MR_ProcLayout *) & \
MR_proc_layout_user_name(module, name, arity, mode), \
0, \
-1, \
MR_FALSE, \
0, \
0, \
-1 /* No info about live values */ \
}
/*-------------------------------------------------------------------------*/
/*
** These macros are used as shorthands in generated C source files
** for some fields of MR_LabelLayouts.
**
** We need to cast the addresses of proc layout structures because there
** are several kinds of proc layouts, of different (though compatible) types.
*/
#define MR_LL(e, port, num, path) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_NOT_HIDDEN, (num), (path), NULL
#define MR_LL_H(e, port, num, path) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_HIDDEN, (num), (path), NULL
#define MR_LL_U(e, port, num, path, ue) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_NOT_HIDDEN, (num), (path), (ue)
#define MR_LL_H_U(e, port, num, path, ue) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_HIDDEN, (num), (path), (ue)
#define MR_LLVS(m, p, h, s) \
&MR_pseudo_type_infos(m)[p], \
&MR_hlds_var_nums(m)[h], \
&MR_short_locns(m)[s]
#define MR_LLVL(m, p, h, s, l) \
&MR_pseudo_type_infos(m)[p], \
&MR_hlds_var_nums(m)[h], \
&MR_short_locns(m)[s], \
&MR_long_locns(m)[l]
#define MR_LLVS0(m, p, h, s) \
0, \
MR_LLVS(m, p, h, s)
#define MR_LLVL0(m, p, h, s, l) \
0, \
MR_LLVL(m, p, h, s, l)
#define MR_LLVSC(m, tpt, tpc, p, h, s) \
(const MR_TypeParamLocns *) MR_COMMON(tpt, tpc), \
MR_LLVS(m, p, h, s)
#define MR_LLVLC(m, tpt, tpc, p, h, s, l) \
(const MR_TypeParamLocns *) MR_COMMON(tpt, tpc), \
MR_LLVL(m, p, h, s, l)
#define MR_cast_to_pti1(r1) \
(MR_PseudoTypeInfo) (r1),
#define MR_cast_to_pti2(r1, r2) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2),
#define MR_cast_to_pti3(r1, r2, r3) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3)
#define MR_cast_to_pti4(r1, r2, r3, r4) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4),
#define MR_cast_to_pti5(r1, r2, r3, r4, r5) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4), \
(MR_PseudoTypeInfo) (r5),
#define MR_cast_to_pti6(r1, r2, r3, r4, r5, r6) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4), \
(MR_PseudoTypeInfo) (r5), \
(MR_PseudoTypeInfo) (r6),
#define MR_cast_to_pti7(r1, r2, r3, r4, r5, r6, r7) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4), \
(MR_PseudoTypeInfo) (r5), \
(MR_PseudoTypeInfo) (r6), \
(MR_PseudoTypeInfo) (r7),
#define MR_cast_to_pti8(r1, r2, r3, r4, r5, r6, r7, r8) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4), \
(MR_PseudoTypeInfo) (r5), \
(MR_PseudoTypeInfo) (r6), \
(MR_PseudoTypeInfo) (r7), \
(MR_PseudoTypeInfo) (r8),
#define MR_cast_to_pti9(r1, r2, r3, r4, r5, r6, r7, r8, r9) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4), \
(MR_PseudoTypeInfo) (r5), \
(MR_PseudoTypeInfo) (r6), \
(MR_PseudoTypeInfo) (r7), \
(MR_PseudoTypeInfo) (r8), \
(MR_PseudoTypeInfo) (r9),
#define MR_cast_to_pti10(r1, r2, r3, r4, r5, r6, r7, r8, r9, r10) \
(MR_PseudoTypeInfo) (r1), \
(MR_PseudoTypeInfo) (r2), \
(MR_PseudoTypeInfo) (r3), \
(MR_PseudoTypeInfo) (r4), \
(MR_PseudoTypeInfo) (r5), \
(MR_PseudoTypeInfo) (r6), \
(MR_PseudoTypeInfo) (r7), \
(MR_PseudoTypeInfo) (r8), \
(MR_PseudoTypeInfo) (r9), \
(MR_PseudoTypeInfo) (r10),
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ProcLayout.
*/
/*
** The MR_TableIoDecl structure.
**
** To enable declarative debugging of I/O actions, the compiler generates one
** of these structures for each I/O primitive. The compiler transforms the
** bodies of those primitives to create a block of memory and fill it in with
** (1) a pointer to the primitive's MR_TableIoDecl structure and (2) the
** values of the primitive's arguments (both input and output, but excluding
** the I/O states). The array of pseudo-typeinfos pointed to by the ptis field
** gives the types of these arguments, while the filtered_arity field gives
** the number of saved arguments, which will be all the arguments except the
** I/O states. The number in this field is the size of the ptis array, and
** the size of the block exclusive of the pointer. The proc field allows us
** to identify the primitive procedure. This is all the information we need
** to describe the I/O action to the user.
*/
typedef struct MR_TableIoDecl_Struct {
const MR_ProcLayout *MR_table_io_decl_proc;
MR_Integer MR_table_io_decl_filtered_arity;
const MR_PseudoTypeInfo *MR_table_io_decl_ptis;
const MR_TypeParamLocns *MR_table_io_decl_type_params;
} MR_TableIoDecl;
/*
** MR_TableInfo: compiler generated information describing the tabling
** data structures used by a procedure.
**
** For I/O tabled procedures, the information is in the io_decl field.
** For other kinds of tabled procedures, it is in the gen field.
** The init field is used for initialization only.
**
** The MR_table_proc field is not const because the structure it points to
** has fields containing statistics, which are updated at runtime.
*/
typedef union {
const void *MR_table_init;
const MR_TableIoDecl *MR_table_io_decl;
const MR_Table_Gen *MR_table_gen;
MR_ProcTableInfo *MR_table_proc;
} MR_TableInfo;
/*
** The MR_StackTraversal structure contains the following fields:
**
** The code_addr field points to the start of the procedure's code.
** This allows the profiler to figure out which procedure a sampled program
** counter belongs to, and allows the debugger to implement retry.
**
** The succip_locn field encodes the location of the saved succip if it is
** saved in a general purpose stack slot. If the succip is saved in a special
** purpose stack slot (as it is for model_non procedures) or if the procedure
** never saves the succip (as in leaf procedures), this field will contain -1.
**
** The stack_slots field gives the number of general purpose stack slots
** in the procedure.
**
** The detism field encodes the determinism of the procedure.
*/
typedef struct MR_StackTraversal_Struct {
MR_Code *MR_trav_code_addr;
MR_LongLval MR_trav_succip_locn;
MR_int_least16_t MR_trav_stack_slots;
MR_Determinism MR_trav_detism;
} MR_StackTraversal;
#define MR_PROC_LAYOUT_IS_UCI(entry) \
MR_PROC_ID_IS_UCI(entry->MR_sle_proc_id)
/*
** The MR_ExecTrace structure contains the following fields.
**
** The call_label field points to the label layout structure for the label
** associated with the call event at the entry to the procedure. The purpose
** of this field is to allow the debugger to find out which variables
** are where on entry, so it can reexecute the procedure if asked to do so
** and if the values of the required variables are still available.
**
** The labels field contains a pointer to an array of pointers to label layout
** structures; the size of the array is given by the num_labels field. The
** initial part of the array will contain a pointer to the label layout
** structure of every interface event in the procedure; the later parts will
** contain a pointer to the label layout structure of every internal event.
** There is no ordering on the events beyond interface first, internal second.
**
** The used_var_names field points to an array that contains offsets
** into the string table, with the offset at index i-1 giving the name of
** variable i (since variable numbers start at one). If a variable has no name
** or cannot be referred to from an event, the offset will be zero, at which
** offset the string table will contain an empty string.
**
** The max_named_var_num field gives the number of elements in the
** used_var_names table, which is also the number of the highest numbered
** named variable. Note that unnamed variables may have numbers higher than
** this.
**
** The max_r_num field tells the debugger which Mercury abstract machine
** registers need saving in MR_trace: besides the special registers, it is
** the general-purpose registers rN for values of N up to and including the
** value of this field. Note that this field contains an upper bound; in
** general, there will be calls to MR_trace at which the number of the highest
** numbered general purpose (i.e. rN) registers is less than this. However,
** storing the upper bound gets us almost all the benefit (of not saving and
** restoring all the thousand rN registers) for a small fraction of the static
** space cost of storing the actual number in label layout structures.
**
** If the procedure is compiled with deep tracing, the maybe_from_full field
** will contain a negative number. If it is compiled with shallow tracing,
** it will contain the number of the stack slot that holds the flag that says
** whether this incarnation of the procedure was called from deeply traced code
** or not. (The determinism of the procedure decides whether the stack slot
** refers to a stackvar or a framevar.)
**
** If tabling of I/O actions is enabled, the maybe_io_seq field will contain
** the number of the stack slot that holds the value the I/O action counter
** had on entry to this procedure. Even procedures that do not have I/O state
** arguments will have such a slot, since they or their descendants may call
** unsafe_perform_io.
**
** If trailing is not enabled, the maybe_trail field will contain a negative
** number. If it is enabled, it will contain number of the first of two stack
** slots used for checkpointing the state of the trail on entry to the
** procedure. The first contains the trail pointer, the second the ticket.
**
** If the procedure lives on the nondet stack, or if it cannot create any
** temporary nondet stack frames, the maybe_maxfr field will contain a negative
** number. If it lives on the det stack, and can create temporary nondet stack
** frames, it will contain the number number of the stack slot that contains the
** value of maxfr on entry, for use in executing the retry debugger command
** from the middle of the procedure.
**
** The eval_method field contains a representation of the evaluation method
** used by the procedure. The retry command needs this information if it is
** to reset the call tables of the procedure invocations being retried.
**
** We cannot put enums into structures as bit fields. To avoid wasting space,
** we put MR_EvalMethodInts into structures instead of MR_EvalMethods
** themselves.
**
** If the procedure is compiled with some form of tabling, the maybe_call_table
** field contains the number of the stack slot through which we can reach the
** call table entry for this call. In forms of tabling which associate a C
** structure (MR_Subgoal, MR_MemoNonRecord) with a call table entry, the slot
** will point to that structure; in other forms of tabling, it will point
** to the call's MR_TableNode.
**
** The flags field encodes boolean properties of the procedure. For now,
** the only property is whether the procedure has a pair of I/O state
** arguments.
**
** If the procedure lives on the nondet stack, or if it cannot create any
** temporary nondet stack frames, the maybe_maxfr field will contain a negative
** number. If it lives on the det stack, and can create temporary nondet stack
** frames, it will contain the number of the stack slot that contains the
** value of maxfr on entry, for use in executing the retry debugger command
** from the middle of the procedure.
*/
#define MR_EVAL_METHOD_MEMO_STRICT MR_EVAL_METHOD_MEMO
#define MR_EVAL_METHOD_MEMO_FAST_LOOSE MR_EVAL_METHOD_MEMO
#define MR_EVAL_METHOD_MEMO_SPECIFIED MR_EVAL_METHOD_MEMO
typedef enum {
MR_EVAL_METHOD_NORMAL,
MR_EVAL_METHOD_LOOP_CHECK,
MR_EVAL_METHOD_MEMO,
MR_EVAL_METHOD_MINIMAL_STACK_COPY,
MR_EVAL_METHOD_MINIMAL_OWN_STACKS_CONSUMER,
MR_EVAL_METHOD_MINIMAL_OWN_STACKS_GENERATOR,
MR_EVAL_METHOD_TABLE_IO,
MR_EVAL_METHOD_TABLE_IO_DECL,
MR_EVAL_METHOD_TABLE_IO_UNITIZE,
MR_EVAL_METHOD_TABLE_IO_UNITIZE_DECL
} MR_EvalMethod;
typedef MR_int_least8_t MR_EvalMethodInt;
typedef enum {
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_NONE),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_BASIC),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_BASIC_USER),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_SHALLOW),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_DEEP),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_DECL_REP)
} MR_TraceLevel;
typedef MR_int_least8_t MR_TraceLevelInt;
typedef struct MR_ExecTrace_Struct {
const MR_LabelLayout *MR_exec_call_label;
const MR_ModuleLayout *MR_exec_module_layout;
const MR_LabelLayout **MR_exec_labels;
MR_uint_least32_t MR_exec_num_labels;
MR_TableInfo MR_exec_table_info;
const MR_uint_least16_t *MR_exec_head_var_nums;
const MR_uint_least32_t *MR_exec_used_var_names;
MR_uint_least16_t MR_exec_num_head_vars;
MR_uint_least16_t MR_exec_max_named_var_num;
MR_uint_least16_t MR_exec_max_r_num;
MR_uint_least16_t MR_exec_max_f_num;
MR_int_least8_t MR_exec_maybe_from_full;
MR_int_least8_t MR_exec_maybe_io_seq;
MR_int_least8_t MR_exec_maybe_trail;
MR_int_least8_t MR_exec_maybe_maxfr;
MR_EvalMethodInt MR_exec_eval_method_CAST_ME;
MR_int_least8_t MR_exec_maybe_call_table;
MR_TraceLevelInt MR_exec_trace_level_CAST_ME;
MR_uint_least8_t MR_exec_flags;
MR_int_least8_t MR_exec_maybe_tail_rec;
} MR_ExecTrace;
#define MR_compute_max_mr_num(max_mr_num, layout) \
do { \
int max_r_num; \
\
max_r_num = (layout)->MR_sll_entry->MR_sle_max_r_num + \
MR_NUM_SPECIAL_REG; \
max_mr_num = MR_max(max_r_num, MR_FIRST_UNREAL_R_SLOT); \
} while (0)
/*
** The code in the compiler that creates the flag field is
** encode_exec_trace_flags in stack_layout.m.
*/
#define MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR 0x1
#define MR_PROC_LAYOUT_FLAG_HAS_HIGHER_ORDER_ARG 0x2
#define MR_trace_find_reused_frames(proc_layout, sp, reused_frames) \
do { \
const MR_ExecTrace *exec_trace; \
int tailrec_slot; \
\
exec_trace = proc_layout->MR_sle_exec_trace; \
if (exec_trace == NULL) { \
(reused_frames) = 0; \
} else { \
tailrec_slot = proc_layout->MR_sle_maybe_tailrec; \
if (tailrec_slot <= 0) { \
(reused_frames) = 0; \
} else { \
if (MR_DETISM_DET_STACK(proc_layout->MR_sle_detism)) { \
(reused_frames) = MR_based_stackvar((sp), tailrec_slot);\
} else { \
MR_fatal_error("tailrec reuses nondet stack frames"); \
} \
} \
} \
} while (0)
/*
** Proc layout structures contain one, two or three substructures.
**
** - The first substructure is the MR_StackTraversal structure, which contains
** information that enables the stack to be traversed, e.g. for accurate gc.
** It is always present if proc layouts are present at all.
**
** - The second group is the MR_ProcId union, which identifies the
** procedure in terms that are meaningful to both humans and machines.
** It will be generated only if the module is compiled with stack tracing,
** execution tracing or profiling. The MR_ProcId union has two alternatives,
** one for user-defined procedures and one for procedures of the compiler
** generated Unify, Index and Compare predicates.
**
** - The third group is everything else. Currently, this consists of
** information that is of interest to the debugger, to the deep profiler,
** or both.
**
** The information that is of interest to the debugger only is stored in
** the MR_ExecTrace structure, which will be generated only if the module
** is compiled with execution tracing. The information that is of interest to
** the deep profiler is stored in the MR_ProcStatic structure, which will be
** generated only if the module is compiled in a deep profiling grade. The
** other fields in the group are of interest to both the debugger and the
** deep profiler, and will be generated if either execution tracing or deep
** profiling is enabled.
**
** If the body_bytes field is NULL, it means that no representation of the
** procedure body is available. If non-NULL, it contains a pointer to an
** array of bytecodes that represents the body of the procedure. The
** bytecode array should be interpreted by the read_proc_rep predicate in
** mdbcomp/program_representation.m (it starts with an encoded form of the
** array's length). Its contents are generated by compiler/prog_rep.m.
**
** The module_common_layout field points to the part of the module layout
** structure of the module containing the procedure that is common to the
** debugger and the deep profiler. Amongst other things, it gives access to
** the string table that the body_bytes fields refers to.
**
** The runtime system considers all proc layout structures to be of type
** MR_ProcLayout, but must use the macros defined below to check for the
** existence of each substructure before accessing the fields of that
** substructure. The macros are MR_PROC_LAYOUT_HAS_PROC_ID to check for the
** MR_ProcId substructure, MR_PROC_LAYOUT_HAS_EXEC_TRACE to check for the
** MR_ExecTrace substructure, and MR_PROC_LAYOUT_HAS_PROC_STATIC to check for
** the MR_ProcStatic substructure.
**
** The reason why some substructures may be missing is to save space.
** If the options with which a module is compiled do not require execution
** tracing, then the MR_ExecTrace substructure will not present, and if the
** options do not require procedure identification, then the MR_ProcId
** substructure will not be present either. The body_bytes and module_layout
** fields cannot be non-NULL unless at least one of exec trace and proc static
** substructures is present, but they are otherwise independent of those
** substructures.
**
** The compiler itself generates proc layout structures using the following
** three types.
**
** - When generating only stack traversal information, the compiler will
** generate proc layout structures of type MR_ProcLayout_Traversal.
**
** - When generating stack traversal and procedure id information, plus
** possibly others, the compiler will generate proc layout structures of
** types MR_ProcLayoutUser and MR_ProcLayoutUCI.
*/
struct MR_ProcLayout_Struct {
MR_StackTraversal MR_sle_traversal;
MR_ProcId MR_sle_proc_id;
MR_STATIC_CODE_CONST MR_ExecTrace *MR_sle_exec_trace;
MR_ProcStatic *MR_sle_proc_static;
const MR_uint_least8_t *MR_sle_body_bytes;
const MR_ModuleCommonLayout *MR_sle_module_common_layout;
};
typedef struct MR_ProcLayoutUser_Struct {
MR_StackTraversal MR_user_traversal;
MR_UserProcId MR_user_id;
MR_STATIC_CODE_CONST MR_ExecTrace *MR_sle_exec_trace;
MR_ProcStatic *MR_sle_proc_static;
const MR_uint_least8_t *MR_sle_body_bytes;
const MR_ModuleCommonLayout *MR_sle_module_common_layout;
} MR_ProcLayoutUser;
typedef struct MR_ProcLayoutUCI_Struct {
MR_StackTraversal MR_uci_traversal;
MR_UCIProcId MR_uci_id;
MR_STATIC_CODE_CONST MR_ExecTrace *MR_sle_exec_trace;
MR_ProcStatic *MR_sle_proc_static;
const MR_uint_least8_t *MR_sle_body_bytes;
const MR_ModuleCommonLayout *MR_sle_module_common_layout;
} MR_ProcLayoutUCI;
typedef struct MR_ProcLayout_Traversal_Struct {
MR_StackTraversal MR_trav_traversal;
MR_Word MR_trav_no_proc_id; /* will be -1 */
} MR_ProcLayout_Traversal;
#define MR_PROC_LAYOUT_HAS_PROC_ID(entry) \
(MR_PROC_ID_EXISTS(entry->MR_sle_proc_id))
#define MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry) \
(MR_PROC_LAYOUT_HAS_PROC_ID(entry) && \
entry->MR_sle_exec_trace != NULL)
#define MR_PROC_LAYOUT_HAS_PROC_STATIC(entry) \
(MR_PROC_LAYOUT_HAS_PROC_ID(entry) && \
entry->MR_sle_proc_static != NULL)
#define MR_PROC_LAYOUT_HAS_THIRD_GROUP(entry) \
(MR_PROC_LAYOUT_HAS_PROC_ID(entry) && \
( entry->MR_sle_exec_trace != NULL \
|| entry->MR_sle_proc_static != NULL))
#define MR_sle_code_addr MR_sle_traversal.MR_trav_code_addr
#define MR_sle_succip_locn MR_sle_traversal.MR_trav_succip_locn
#define MR_sle_stack_slots MR_sle_traversal.MR_trav_stack_slots
#define MR_sle_detism MR_sle_traversal.MR_trav_detism
#define MR_sle_user MR_sle_proc_id.MR_proc_user
#define MR_sle_uci MR_sle_proc_id.MR_proc_uci
#define MR_sle_call_label MR_sle_exec_trace->MR_exec_call_label
#define MR_sle_module_layout MR_sle_exec_trace->MR_exec_module_layout
#define MR_sle_labels MR_sle_exec_trace->MR_exec_labels
#define MR_sle_num_labels MR_sle_exec_trace->MR_exec_num_labels
#define MR_sle_tabling_pointer MR_sle_exec_trace->MR_exec_tabling_pointer
#define MR_sle_table_info MR_sle_exec_trace->MR_exec_table_info
#define MR_sle_head_var_nums MR_sle_exec_trace->MR_exec_head_var_nums
#define MR_sle_num_head_vars MR_sle_exec_trace->MR_exec_num_head_vars
#define MR_sle_used_var_names MR_sle_exec_trace->MR_exec_used_var_names
#define MR_sle_max_named_var_num MR_sle_exec_trace->MR_exec_max_named_var_num
#define MR_sle_max_r_num MR_sle_exec_trace->MR_exec_max_r_num
#define MR_sle_max_f_num MR_sle_exec_trace->MR_exec_max_f_num
#define MR_sle_maybe_from_full MR_sle_exec_trace->MR_exec_maybe_from_full
#define MR_sle_maybe_io_seq MR_sle_exec_trace->MR_exec_maybe_io_seq
#define MR_sle_maybe_trail MR_sle_exec_trace->MR_exec_maybe_trail
#define MR_sle_maybe_maxfr MR_sle_exec_trace->MR_exec_maybe_maxfr
#define MR_sle_maybe_call_table MR_sle_exec_trace->MR_exec_maybe_call_table
#define MR_sle_maybe_decl_debug MR_sle_exec_trace->MR_exec_maybe_decl_debug
#define MR_sle_maybe_tailrec MR_sle_exec_trace->MR_exec_maybe_tail_rec
#define MR_sle_eval_method(proc_layout_ptr) \
((MR_EvalMethod) (proc_layout_ptr)-> \
MR_sle_exec_trace->MR_exec_eval_method_CAST_ME)
#define MR_sle_trace_level(proc_layout_ptr) \
((MR_TraceLevel) (proc_layout_ptr)-> \
MR_sle_exec_trace->MR_exec_trace_level_CAST_ME)
#define MR_proc_has_io_state_pair(proc_layout_ptr) \
((proc_layout_ptr)->MR_sle_exec_trace->MR_exec_flags \
& MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR)
#define MR_proc_has_higher_order_arg(proc_layout_ptr) \
((proc_layout_ptr)->MR_sle_exec_trace->MR_exec_flags \
& MR_PROC_LAYOUT_FLAG_HAS_HIGHER_ORDER_ARG)
/* Adjust the arity of functions for printing. */
#define MR_sle_user_adjusted_arity(entry) \
((entry)->MR_sle_user.MR_user_arity - \
(((entry)->MR_sle_user.MR_user_pred_or_func == MR_FUNCTION) ? 1 : 0))
#define MR_MAX_VARNAME_SIZE 160
/*
** Return the name (if any) of the variable with the given HLDS variable number
** in the procedure indicated by the first argument.
**
** The name will actually be found by MR_name_in_string_table, so the
** comments there about name size and should_copy apply here as well.
*/
extern MR_ConstString MR_hlds_var_name(const MR_ProcLayout *entry,
int hlds_var_num, int *should_copy);
/*
** Return the name (if any) of the variable with the given name code
** in the given string table.
**
** Sometimes, the returned name will point to static, const storage,
** whose contents are valid until the end of the program's execution,
** while at other times, it will point to a buffer whose contents
** will be valid only until the next call to MR_name_in_string_table.
**
** Callers that want to know which is the case should pass a non-NULL
** value for should_copy. The returned name will point to the buffer
** if and only if *should_copy is true. The size of the buffer is
** MR_MAX_VARNAME_SIZE bytes.
*/
extern MR_ConstString MR_name_in_string_table(const char *string_table,
MR_Integer string_table_size,
MR_uint_least32_t name_code, int *should_copy);
/*
** Given a string, see whether its end consists a sequence of digits.
** If yes, return the offset of the first digit in this sequence relative
** to the start of the string. Otherwise, return a negative number.
*/
extern int MR_find_start_of_num_suffix(const char *str);
/*
** Define a layout structure for a procedure, containing information
** for stack traversal and procedure identification.
**
** The slot count and the succip location parameters do not have to be
** supplied for procedures that live on the nondet stack, since for such
** procedures the size of the frame can be deduced from the prevfr field
** and the location of the succip is fixed.
**
** An unknown slot count should be signalled by MR_PROC_NO_SLOT_COUNT.
** An unknown succip location should be signalled by MR_LONG_LVAL_TYPE_UNKNOWN.
**
** For the procedure identification, we always use the same module name
** for the defining and declaring modules, since procedures whose code
** is hand-written as C modules cannot be inlined in other Mercury modules.
**
** Due to the possibility that code addresses are not static, any use of
** the MR_MAKE_PROC_ID_PROC_LAYOUT macro has to be accompanied by a call to the
** MR_INIT_PROC_LAYOUT_ADDR macro in the initialization code of the C module
** that defines the entry. (The cast in the body of MR_INIT_PROC_LAYOUT_ADDR
** is needed because compiler-generated layout structures may use any of the
** variant types listed above.)
*/
#define MR_PROC_NO_SLOT_COUNT -1
#ifdef MR_STATIC_CODE_ADDRESSES
#define MR_MAKE_PROC_LAYOUT_ADDR(entry) MR_ENTRY(entry)
#define MR_INIT_PROC_LAYOUT_ADDR(entry) do { } while (0)
#else
#define MR_MAKE_PROC_LAYOUT_ADDR(entry) ((MR_Code *) NULL)
#define MR_INIT_PROC_LAYOUT_ADDR(entry) \
do { \
((MR_ProcLayout *) & \
MR_PASTE2(mercury_data__proc_layout__, entry)) \
->MR_sle_code_addr = MR_ENTRY(entry); \
} while (0)
#endif
#define MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(sc, detism, slots, succip_locn, \
pf, module, name, arity, mode, proc_static) \
MR_declare_entry(MR_proc_entry_user_name(module, name, \
arity, mode)); \
sc const MR_ProcLayoutUser \
MR_proc_layout_user_name(module, name, arity, mode) = { \
{ \
MR_MAKE_PROC_LAYOUT_ADDR( \
MR_proc_entry_user_name(module, name, \
arity, mode)), \
succip_locn, \
slots, \
detism \
}, \
{ \
pf, \
MR_STRINGIFY(module), \
MR_STRINGIFY(module), \
MR_STRINGIFY(name), \
arity, \
mode \
}, \
NULL, \
(MR_ProcStatic *) proc_static \
}
#define MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(sc, detism, slots, succip_locn, \
module, name, type, arity, mode, proc_static) \
MR_declare_entry(MR_proc_entry_uci_name(module, name, \
type, arity, mode)); \
sc const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(module, name, type, arity, mode) = { \
{ \
MR_MAKE_PROC_LAYOUT_ADDR( \
MR_proc_entry_uci_name(module, name, \
type, arity, mode)), \
succip_locn, \
slots, \
detism \
}, \
{ \
MR_STRINGIFY(type), \
MR_STRINGIFY(module), \
MR_STRINGIFY(module), \
MR_STRINGIFY(name), \
arity, \
mode \
}, \
NULL, \
(MR_ProcStatic *) proc_static \
}
#define MR_NO_EXTERN_DECL
#define MR_STATIC_USER_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(static, detism, slots, \
succip_locn, pf, module, name, arity, mode, \
&MR_proc_static_user_name(module, name, arity, mode))
#define MR_EXTERN_USER_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots, \
succip_locn, pf, module, name, arity, mode, \
&MR_proc_static_user_name(module, name, arity, mode))
#define MR_STATIC_UCI_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
module, name, type, arity, mode) \
MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(static, detism, slots, \
succip_locn, module, name, type, arity, mode, \
&MR_proc_static_uci_name(module, name, type, arity, mode))
#define MR_EXTERN_UCI_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
module, name, type, arity, mode) \
MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots, \
succip_locn, module, name, type, arity, mode, \
&MR_proc_static_uci_name(module, name, type, arity, mode))
#define MR_STATIC_USER_PROC_ID_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(static, detism, slots, \
succip_locn, pf, module, name, arity, mode, NULL)
#define MR_EXTERN_USER_PROC_ID_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots, \
succip_locn, pf, module, name, arity, mode, NULL)
#define MR_DECLARE_UCI_PROC_STATIC_LAYOUTS(mod, n, a) \
const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(mod, __Unify__, n, a, 0); \
const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(mod, __Compare__, n, a, 0); \
const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(mod, __CompareRep__, n, a, 0);
/*
** In procedures compiled with execution tracing, three items are stored
** in stack slots with fixed numbers. They are:
**
** the event number of the last event before the call event,
** the call number, and
** the call depth.
**
** Note that the first slot does not store the number of the call event
** itself, but rather the number of the call event minus one. The reason
** for this is that (a) incrementing the number stored in this slot would
** increase executable size, and (b) if the procedure is shallow traced,
** MR_trace may not be called for the call event, so we cannot shift the
** burden of initializing fields to the MR_trace of the call event either.
**
** The following macros will access the fixed slots. They can be used whenever
** MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry) is true; which set you should use
** depends on the determinism of the procedure.
**
** These macros have to be kept in sync with compiler/trace.m.
*/
#define MR_event_num_framevar(base_curfr) MR_based_framevar(base_curfr, 1)
#define MR_call_num_framevar(base_curfr) MR_based_framevar(base_curfr, 2)
#define MR_call_depth_framevar(base_curfr) MR_based_framevar(base_curfr, 3)
#define MR_event_num_stackvar(base_sp) MR_based_stackvar(base_sp, 1)
#define MR_call_num_stackvar(base_sp) MR_based_stackvar(base_sp, 2)
#define MR_call_depth_stackvar(base_sp) MR_based_stackvar(base_sp, 3)
/*
** In model_non procedures compiled with --trace-redo, one or two other items
** are stored in fixed stack slots. These are
**
** the address of the layout structure for the redo event
** the saved copy of the from-full flag (only if trace level is shallow)
**
** The following macros will access these slots. They should be used only from
** within the code that calls MR_trace for the REDO event.
**
** This macros have to be kept in sync with compiler/trace.m.
*/
#define MR_redo_layout_framevar(base_curfr) MR_based_framevar(base_curfr, 4)
#define MR_redo_fromfull_framevar(base_curfr) MR_based_framevar(base_curfr, 5)
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ModuleLayout.
**
** The layout structure for a module contains the following fields.
**
** The MR_ml_name field contains the name of the module.
**
** The MR_ml_string_table field contains the module's string table, which
** contains strings referred to by other layout structures in the module
** (initially only the tables containing variables names, referred to from
** label layout structures). The MR_ml_string_table_size field gives the size
** of the table in bytes.
**
** The MR_ml_procs field points to an array containing pointers to the proc
** layout structures of all the procedures in the module; the MR_ml_proc_count
** field gives the number of entries in the array.
**
** The MR_ml_module_file_layout field points to an array of N file layout
** pointers if the module has labels corresponding to contexts that refer
** to the names of N files. For each file, the table gives its name, the
** number of labels in that file in this module, and for each such label,
** it gives its line number and a pointer to its label layout struct.
** The corresponding elements of the label_lineno and label_layout arrays
** refer to the same label. (The reason why they are not stored together
** is space efficiency; adding a 16 bit field to a label layout structure would
** require padding.) The labels are sorted on line number.
**
** The MR_ml_trace_level field gives the trace level that the module was
** compiled with. If the MR_TraceLevel enum is modified, then the
** corresponding function in compiler/trace_params.m must also be updated.
**
** The MR_ml_suppressed_events events field encodes the set of event types
** (ports) that were suppressed when generating code for this module. The bit
** given by the expression (1 << MR_PORT_<PORTTYPE>) will be set in this
** integer iff trace port MR_PORT_<PORTTYPE> is suppressed.
**
** The MR_ml_label_exec_count field points to an array of integers, with each
** integer holding the number of times execution has reached a given label.
** Each label's layout structure records the index of that label in this array.
** The most direct way to go the other way, to find out which label owns a
** particular slot in this array, is to search the label arrays in the file
** layout structures, and test their MR_sll_label_num_in_module fields.
** (If we needed faster access, we could add another array with elements
** corresponding to MR_ml_label_exec_count's pointing to the labels' layout
** structures.)
**
** The MR_ml_num_label_exec_counts field contains the number of elements
** in the MR_ml_label_exec_count array.
*/
typedef struct MR_ModuleFileLayout_Struct {
MR_ConstString MR_mfl_filename;
MR_Integer MR_mfl_label_count;
/* the following fields point to arrays of size MR_mfl_label_count */
const MR_int_least16_t *MR_mfl_label_lineno;
const MR_LabelLayout **MR_mfl_label_layout;
} MR_ModuleFileLayout;
/*
** The version of the data structures in this file -- useful for bootstrapping.
** If you write runtime code that checks this version number and can at least
** handle the previous version of the data structure, it makes it easier to
** bootstrap changes to these data structures.
**
** This number should be kept in sync with layout_version_number in
** compiler/layout_out.m.
*/
#define MR_LAYOUT_VERSION MR_LAYOUT_VERSION__COMMON
#define MR_LAYOUT_VERSION__USER_DEFINED 1
#define MR_LAYOUT_VERSION__EVENTSETNAME 2
#define MR_LAYOUT_VERSION__SYNTH_ATTR 3
#define MR_LAYOUT_VERSION__COMMON 4
struct MR_ModuleCommonLayout_Struct {
MR_uint_least8_t MR_mlc_version_number;
MR_ConstString MR_mlc_name;
MR_Integer MR_mlc_string_table_size;
const char *MR_mlc_string_table;
};
struct MR_ModuleLayout_Struct {
const MR_ModuleCommonLayout *MR_ml_common;
MR_Integer MR_ml_proc_count;
const MR_ProcLayout **MR_ml_procs;
MR_Integer MR_ml_filename_count;
const MR_ModuleFileLayout **MR_ml_module_file_layout;
MR_TraceLevel MR_ml_trace_level;
MR_int_least32_t MR_ml_suppressed_events;
MR_int_least32_t MR_ml_num_label_exec_counts;
MR_Unsigned *MR_ml_label_exec_count;
const char *MR_ml_user_event_set_name;
const char *MR_ml_user_event_set_desc;
MR_int_least16_t MR_ml_user_event_max_num_attr;
MR_int_least16_t MR_ml_num_user_event_specs;
MR_UserEventSpec *MR_ml_user_event_specs;
};
#define MR_ml_version_number MR_ml_common->MR_mlc_version_number
#define MR_ml_name MR_ml_common->MR_mlc_name
#define MR_ml_string_table_size MR_ml_common->MR_mlc_string_table_size
#define MR_ml_string_table MR_ml_common->MR_mlc_string_table
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ClosureId.
**
** Each closure contains an MR_ClosureId structure. The proc_id field
** identifies the procedure called by the closure. The other fields identify
** the context where the closure was created.
**
** The compiler generates closure id structures as either MR_UserClosureId
** or MR_UCIClosureId structures in order to avoid initializing the
** MR_ProcId union through an inappropriate member.
*/
struct MR_ClosureId_Struct {
MR_ProcId MR_closure_proc_id;
MR_ConstString MR_closure_module_name;
MR_ConstString MR_closure_file_name;
MR_Integer MR_closure_line_number;
MR_ConstString MR_closure_goal_path;
};
struct MR_UserClosureId_Struct {
MR_UserProcId MR_user_closure_proc_id;
MR_ConstString MR_user_closure_module_name;
MR_ConstString MR_user_closure_file_name;
MR_Integer MR_user_closure_line_number;
MR_ConstString MR_user_closure_goal_path;
};
struct MR_UCIClosureId_Struct {
MR_UCIProcId MR_uci_closure_proc_id;
MR_ConstString MR_uci_closure_module_name;
MR_ConstString MR_uci_closure_file_name;
MR_Integer MR_uci_closure_line_number;
MR_ConstString MR_uci_closure_goal_path;
};
#endif /* not MERCURY_STACK_LAYOUT_H */