mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 14:57:03 +00:00
Estimated hours taken: 0.1 Branches: main runtime/mercury_misc.h: runtime/mercury_stack_layout.h: Remove the macros that we don't generate anymore. This completes the bootstrap of the diff that reorganized the handling of static cells to use arrays instead of individual variables.
1268 lines
50 KiB
C
1268 lines
50 KiB
C
/*
|
|
** Copyright (C) 1998-2006 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_Proc_Id */
|
|
#include "mercury_goto.h" /* for MR_PROC_LAYOUT etc */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** 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_Long_Lval and MR_Short_Lval
|
|
*/
|
|
|
|
/*
|
|
** MR_Long_Lval is a MR_uint_least32_t which describes an 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_Long_Lval refers to is encoded using
|
|
** a low tag with MR_LONG_LVAL_TAGBITS bits; the type MR_Long_Lval_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_f(Num) 1 Num (register number)
|
|
** MR_stackvar(Num) 2 Num (stack slot number)
|
|
** MR_framevar(Num) 3 Num (stack slot number)
|
|
** MR_succip 4
|
|
** MR_maxfr 5
|
|
** MR_curfr 6
|
|
** MR_hp 7
|
|
** MR_sp 8
|
|
** indirect(Base, N) 9 See below
|
|
** unknown 10 (The location is not known)
|
|
**
|
|
** 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_Long_Lval value giving the location of the pointer to the
|
|
** type class info. This MR_Long_Lval 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_uint_least32_t MR_Long_Lval;
|
|
|
|
typedef enum {
|
|
MR_LONG_LVAL_TYPE_R,
|
|
MR_LONG_LVAL_TYPE_F,
|
|
MR_LONG_LVAL_TYPE_STACKVAR,
|
|
MR_LONG_LVAL_TYPE_FRAMEVAR,
|
|
MR_LONG_LVAL_TYPE_SUCCIP,
|
|
MR_LONG_LVAL_TYPE_MAXFR,
|
|
MR_LONG_LVAL_TYPE_CURFR,
|
|
MR_LONG_LVAL_TYPE_HP,
|
|
MR_LONG_LVAL_TYPE_SP,
|
|
MR_LONG_LVAL_TYPE_INDIRECT,
|
|
MR_LONG_LVAL_TYPE_UNKNOWN
|
|
} MR_Long_Lval_Type;
|
|
|
|
/* This must be in sync with stack_layout__long_lval_tag_bits */
|
|
#define MR_LONG_LVAL_TAGBITS 4
|
|
|
|
#define MR_LONG_LVAL_TYPE(Locn) \
|
|
((MR_Long_Lval_Type) \
|
|
(((MR_Word) Locn) & ((1 << MR_LONG_LVAL_TAGBITS) - 1)))
|
|
|
|
#define MR_LONG_LVAL_NUMBER(Locn) \
|
|
((int) ((MR_Word) Locn) >> MR_LONG_LVAL_TAGBITS)
|
|
|
|
/* 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(LocnNumber) \
|
|
(((MR_Word) (LocnNumber)) >> MR_LONG_LVAL_OFFSETBITS)
|
|
|
|
#define MR_LONG_LVAL_STACKVAR(n) \
|
|
((MR_Word) ((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_STACKVAR)
|
|
|
|
#define MR_LONG_LVAL_FRAMEVAR(n) \
|
|
((MR_Word) ((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_FRAMEVAR)
|
|
|
|
#define MR_LONG_LVAL_R_REG(n) \
|
|
((MR_Word) ((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_R)
|
|
|
|
/*
|
|
** MR_Short_Lval 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_Long_Lval refers to is encoded using
|
|
** a low tag with 2 bits; the type MR_Short_Lval_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_Long_Lval_Type
|
|
**
|
|
** 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_Short_Lval;
|
|
|
|
typedef enum {
|
|
MR_SHORT_LVAL_TYPE_R,
|
|
MR_SHORT_LVAL_TYPE_STACKVAR,
|
|
MR_SHORT_LVAL_TYPE_FRAMEVAR,
|
|
MR_SHORT_LVAL_TYPE_SPECIAL
|
|
} MR_Short_Lval_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_Short_Lval_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_Short_Lval) (((n) << MR_SHORT_LVAL_TAGBITS) \
|
|
+ MR_SHORT_LVAL_TYPE_STACKVAR))
|
|
|
|
#define MR_SHORT_LVAL_FRAMEVAR(n) \
|
|
((MR_Short_Lval) (((n) << MR_SHORT_LVAL_TAGBITS) \
|
|
+ MR_SHORT_LVAL_TYPE_FRAMEVAR))
|
|
|
|
#define MR_SHORT_LVAL_R_REG(n) \
|
|
((MR_Short_Lval) (((n) << MR_SHORT_LVAL_TAGBITS) \
|
|
+ MR_SHORT_LVAL_TYPE_R))
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Label_Layout
|
|
*/
|
|
|
|
/*
|
|
** An MR_Label_Layout 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_Trace_Port. 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 true if the
|
|
** event should have no effects that the user can see (no message printed, no
|
|
** increment of the event number etc), and false 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.
|
|
**
|
|
** 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 last three fields are
|
|
** meaningful; if it is not available, the macro will return false and the last
|
|
** three fields are not meaningful (i.e. you are looking at an
|
|
** MR_Label_Layout_No_Var_Info 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_Short_Lval
|
|
** or as a 32-bit MR_Long_Lval. We prefer representing a location as an
|
|
** MR_Short_Lval, but of course not all locations can be represented in
|
|
** this way, so those other locations are represented as MR_Long_Lvals.
|
|
**
|
|
** 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_Short_Lval 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_locns_types field points to a memory area that contains three
|
|
** vectors back to back. The first vector has #Long + #Short word-sized
|
|
** elements, each of which is a pointer to a MR_PseudoTypeInfo 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). The second
|
|
** vector is an array of #Long MR_Long_Lvals, and the third is an array of
|
|
** #Short MR_Short_Lvals, each of which describes a location. The
|
|
** pseudotypeinfo pointed to by the slot at subscript i in the first vector
|
|
** describes the type of the data stored in slot i in the second vector if
|
|
** i < #Long, and the type of the data stored in slot i - #Long in the third
|
|
** vector otherwise.
|
|
**
|
|
** 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_Type_Param_Locns 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 first vector
|
|
** pointed to by the MR_sll_locns_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
|
|
** corresponding to an event.
|
|
**
|
|
** XXX: Presently, inst information is ignored; we assume that all live values
|
|
** are ground.
|
|
*/
|
|
|
|
struct MR_Type_Param_Locns_Struct {
|
|
MR_uint_least32_t MR_tp_param_count;
|
|
MR_Long_Lval MR_tp_param_locns[MR_VARIABLE_SIZED];
|
|
};
|
|
|
|
struct MR_Label_Layout_Struct {
|
|
const MR_Proc_Layout *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;
|
|
MR_Integer MR_sll_var_count; /* >= 0 */
|
|
const void *MR_sll_locns_types;
|
|
const MR_uint_least16_t *MR_sll_var_nums;
|
|
const MR_Type_Param_Locns *MR_sll_tvars;
|
|
};
|
|
|
|
typedef struct MR_Label_Layout_No_Var_Info_Struct {
|
|
const MR_Proc_Layout *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;
|
|
MR_Integer MR_sll_var_count; /* < 0 */
|
|
} MR_Label_Layout_No_Var_Info;
|
|
|
|
#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) \
|
|
: "")
|
|
|
|
#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_long_desc_var_count(sll) \
|
|
(((sll)->MR_sll_var_count) >> MR_SHORT_COUNT_BITS)
|
|
#define MR_short_desc_var_count(sll) \
|
|
(((sll)->MR_sll_var_count) & MR_SHORT_COUNT_MASK)
|
|
#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) \
|
|
(((MR_PseudoTypeInfo *) ((sll)->MR_sll_locns_types))[(i)])
|
|
#define MR_end_of_var_ptis(sll) \
|
|
(&MR_var_pti((sll), MR_all_desc_var_count(sll)))
|
|
#define MR_long_desc_var_locn(sll, i) \
|
|
(((MR_uint_least32_t *) MR_end_of_var_ptis(sll))[(i)])
|
|
#define MR_end_of_long_desc_var_locns(sll) \
|
|
(&MR_long_desc_var_locn((sll), MR_long_desc_var_count(sll)))
|
|
#define MR_short_desc_var_locn(sll, i) \
|
|
(((MR_uint_least8_t *) \
|
|
MR_end_of_long_desc_var_locns(sll)) \
|
|
[((i) - MR_long_desc_var_count(sll))])
|
|
|
|
/*
|
|
** 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_Label_Layout *) &MR_LAYOUT_FROM_LABEL(MR_add_prefix(label)))
|
|
|
|
#define MR_MAKE_USER_INTERNAL_LAYOUT(module, name, arity, mode, label) \
|
|
MR_Label_Layout_No_Var_Info \
|
|
MR_label_layout_user_name(module, name, arity, mode, label) = { \
|
|
(MR_Proc_Layout *) & \
|
|
MR_proc_layout_user_name(module, name, arity, mode), \
|
|
-1, \
|
|
MR_FALSE, \
|
|
0, \
|
|
0, \
|
|
-1 /* No info about live values */ \
|
|
}
|
|
|
|
/*
|
|
** These macros are used as shorthands in generated C source files.
|
|
** The first two arguments are the entry label name and the label number;
|
|
** the others are the fields of MR_Label_Layouts.
|
|
*/
|
|
|
|
#define MR_DEF_LL_GEN(e, ln, port, h, num, path, vc, lt, vn, tv) \
|
|
static const MR_Label_Layout \
|
|
MR_LABEL_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)) \
|
|
= { \
|
|
MR_PROC_LAYOUT(MR_add_prefix(e)), \
|
|
MR_PASTE2(MR_PORT_, port), \
|
|
(h), (num), (path), (vc), \
|
|
((const void *) lt), \
|
|
((const MR_uint_least16_t *) vn), \
|
|
((const MR_Type_Param_Locns *) tv) \
|
|
}
|
|
|
|
#define MR_DEF_LLNVI_GEN(e, ln, port, h, num, path) \
|
|
static const MR_Label_Layout_No_Var_Info \
|
|
MR_LABEL_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)) \
|
|
= { \
|
|
MR_PROC_LAYOUT(MR_add_prefix(e)), \
|
|
MR_PASTE2(MR_PORT_, port), \
|
|
(h), (path), (num), -1 \
|
|
}
|
|
|
|
#define MR_DEF_LL(e, ln, port, num, path, vc, lt, vn, tv) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, vc, lt, vn, tv)
|
|
|
|
#define MR_DEF_LLT(e, ln, port, num, path, vc, lt, vn, tv) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, vc, lt, vn, tv)
|
|
|
|
#define MR_DEF_LLXCCC(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc, tvt, tvc)\
|
|
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, vc, \
|
|
MR_XCOMMON(ltt, ltc), \
|
|
MR_XCOMMON(vnt, vnc), \
|
|
MR_XCOMMON(tvt, tvc))
|
|
|
|
#define MR_DEF_LLXCC0(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, vc, \
|
|
MR_XCOMMON(ltt, ltc), \
|
|
MR_XCOMMON(vnt, vnc), 0)
|
|
|
|
#define MR_DEF_LLTXCCC(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc, tvt,tvc)\
|
|
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, vc, \
|
|
MR_XCOMMON(ltt, ltc), \
|
|
MR_XCOMMON(vnt, vnc), \
|
|
MR_XCOMMON(tvt, tvc))
|
|
|
|
#define MR_DEF_LLTXCC0(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, vc, \
|
|
MR_XCOMMON(ltt, ltc), \
|
|
MR_XCOMMON(vnt, vnc), 0)
|
|
|
|
#define MR_DEF_LLNVI(e, ln, port, num, path) \
|
|
MR_DEF_LLNVI_GEN(e, ln, port, MR_FALSE, path)
|
|
|
|
#define MR_DEF_LLNVIT(e, ln, port, num, path) \
|
|
MR_DEF_LLNVI_GEN(e, ln, port, MR_TRUE, path)
|
|
|
|
#define MR_DECL_LL(e, ln) \
|
|
MR_declare_label(MR_label_name(MR_add_prefix(e), ln)); \
|
|
static const MR_Label_Layout \
|
|
MR_LABEL_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)); \
|
|
|
|
#define MR_DECL_LLNVI(e, ln) \
|
|
MR_declare_label(MR_label_name(MR_add_prefix(e), ln)); \
|
|
static const MR_Label_Layout_No_Var_Info \
|
|
MR_LABEL_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)); \
|
|
|
|
#define MR_DECL_LL1(e, ln1) \
|
|
MR_DECL_LL(e, ln1)
|
|
|
|
#define MR_DECL_LL2(e, ln1, ln2) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2)
|
|
|
|
#define MR_DECL_LL3(e, ln1, ln2, ln3) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3)
|
|
|
|
#define MR_DECL_LL4(e, ln1, ln2, ln3, ln4) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4)
|
|
|
|
#define MR_DECL_LL5(e, ln1, ln2, ln3, ln4, ln5) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4) \
|
|
MR_DECL_LL(e, ln5)
|
|
|
|
#define MR_DECL_LL6(e, ln1, ln2, ln3, ln4, ln5, ln6) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4) \
|
|
MR_DECL_LL(e, ln5) \
|
|
MR_DECL_LL(e, ln6)
|
|
|
|
#define MR_DECL_LL7(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4) \
|
|
MR_DECL_LL(e, ln5) \
|
|
MR_DECL_LL(e, ln6) \
|
|
MR_DECL_LL(e, ln7)
|
|
|
|
#define MR_DECL_LL8(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4) \
|
|
MR_DECL_LL(e, ln5) \
|
|
MR_DECL_LL(e, ln6) \
|
|
MR_DECL_LL(e, ln7) \
|
|
MR_DECL_LL(e, ln8)
|
|
|
|
#define MR_DECL_LL9(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8, ln9) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4) \
|
|
MR_DECL_LL(e, ln5) \
|
|
MR_DECL_LL(e, ln6) \
|
|
MR_DECL_LL(e, ln7) \
|
|
MR_DECL_LL(e, ln8) \
|
|
MR_DECL_LL(e, ln9)
|
|
|
|
#define MR_DECL_LL10(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8, ln9, ln10) \
|
|
MR_DECL_LL(e, ln1) \
|
|
MR_DECL_LL(e, ln2) \
|
|
MR_DECL_LL(e, ln3) \
|
|
MR_DECL_LL(e, ln4) \
|
|
MR_DECL_LL(e, ln5) \
|
|
MR_DECL_LL(e, ln6) \
|
|
MR_DECL_LL(e, ln7) \
|
|
MR_DECL_LL(e, ln8) \
|
|
MR_DECL_LL(e, ln9) \
|
|
MR_DECL_LL(e, ln10)
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Proc_Layout
|
|
*/
|
|
|
|
/*
|
|
** The MR_Table_Io_Decl 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_Table_Io_Decl 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_Table_Io_Decl_Struct {
|
|
const MR_Proc_Layout *MR_table_io_decl_proc;
|
|
MR_Integer MR_table_io_decl_filtered_arity;
|
|
const MR_PseudoTypeInfo *MR_table_io_decl_ptis;
|
|
const MR_Type_Param_Locns *MR_table_io_decl_type_params;
|
|
} MR_Table_Io_Decl;
|
|
|
|
/*
|
|
** The MR_Table_Gen structure.
|
|
**
|
|
** To enable debugging (especially performance debugging) of tabled predicates,
|
|
** the compiler generates one of these structures for each tabled predicate
|
|
** (except I/O primitives, for which it generates an MR_Table_Io_Decl
|
|
** structure.)
|
|
**
|
|
** Each argument of a tabled predicate is an input or an output. Inputs are put
|
|
** into the call trie, which has one level per input argument. The structure of
|
|
** each level depends on what kind of type the corresponding input argument is;
|
|
** this is recorded in the input_steps field, which points to an array of size
|
|
** num_inputs. If the type is an enum, we cannot interpret the data structures
|
|
** used on that level without also knowing how many alternatives the type has;
|
|
** this is recorded in the corresponding element of the enum_params array,
|
|
** which is likewise of size num_inputs. (Elements of the enum_params array
|
|
** that correspond to arguments whose types are not enums are not meaningful.)
|
|
**
|
|
** The ptis field points to an array of pseudotypeinfos of size num_inputs +
|
|
** num_outputs. The first num_inputs elements give the types of the input
|
|
** arguments, while the remaining num_outputs elements give the types of the
|
|
** output arguments.
|
|
*/
|
|
|
|
typedef enum {
|
|
MR_TABLE_STEP_DUMMY,
|
|
MR_TABLE_STEP_INT,
|
|
MR_TABLE_STEP_CHAR,
|
|
MR_TABLE_STEP_STRING,
|
|
MR_TABLE_STEP_FLOAT,
|
|
MR_TABLE_STEP_ENUM,
|
|
MR_TABLE_STEP_USER,
|
|
MR_TABLE_STEP_USER_FAST_LOOSE,
|
|
MR_TABLE_STEP_POLY,
|
|
MR_TABLE_STEP_POLY_FAST_LOOSE,
|
|
MR_TABLE_STEP_TYPEINFO,
|
|
MR_TABLE_STEP_TYPECLASSINFO,
|
|
MR_TABLE_STEP_PROMISE_IMPLIED
|
|
} MR_Table_Trie_Step;
|
|
|
|
typedef struct MR_Table_Gen_Struct {
|
|
int MR_table_gen_num_inputs;
|
|
int MR_table_gen_num_outputs;
|
|
const MR_Table_Trie_Step *MR_table_gen_input_steps;
|
|
const MR_Integer *MR_table_gen_enum_params;
|
|
const MR_PseudoTypeInfo *MR_table_gen_ptis;
|
|
const MR_Type_Param_Locns *MR_table_gen_type_params;
|
|
} MR_Table_Gen;
|
|
|
|
/*
|
|
** MR_Table_Info: 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.
|
|
*/
|
|
|
|
typedef union {
|
|
const void *MR_table_init;
|
|
const MR_Table_Io_Decl *MR_table_io_decl;
|
|
const MR_Table_Gen *MR_table_gen;
|
|
} MR_Table_Info;
|
|
|
|
/*
|
|
** The MR_Stack_Traversal 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_Stack_Traversal_Struct {
|
|
MR_Code *MR_trav_code_addr;
|
|
MR_Long_Lval MR_trav_succip_locn;
|
|
MR_int_least16_t MR_trav_stack_slots;
|
|
MR_Determinism MR_trav_detism;
|
|
} MR_Stack_Traversal;
|
|
|
|
#define MR_PROC_LAYOUT_IS_UCI(entry) \
|
|
MR_PROC_ID_IS_UCI(entry->MR_sle_proc_id)
|
|
|
|
/*
|
|
** The MR_Exec_Trace 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 module_layout field points to the module info structure of the module
|
|
** containing the procedure. This allows the debugger access to the string table
|
|
** stored there, as well the table associating source-file contexts with labels.
|
|
**
|
|
** The body_bytes field contains a pointer to an array of bytecodes that
|
|
** represents the body of the procedure. It will be a null pointer if no
|
|
** representation is available. If it is not null pointer, then it should
|
|
** be interpreted by read_proc_rep in browser/declarative_execution.m.
|
|
**
|
|
** 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.
|
|
*/
|
|
|
|
typedef enum {
|
|
MR_EVAL_METHOD_NORMAL,
|
|
MR_EVAL_METHOD_LOOP_CHECK,
|
|
MR_EVAL_METHOD_MEMO_STRICT,
|
|
MR_EVAL_METHOD_MEMO_FAST_LOOSE,
|
|
MR_EVAL_METHOD_MEMO_SPECIFIED,
|
|
MR_EVAL_METHOD_MINIMAL_STACK_COPY,
|
|
MR_EVAL_METHOD_MINIMAL_OWN_STACKS,
|
|
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_TRACELEVEL_NONE,
|
|
MR_TRACELEVEL_SHALLOW,
|
|
MR_TRACELEVEL_DEEP,
|
|
MR_TRACELEVEL_DECL_REP
|
|
} MR_TraceLevel;
|
|
|
|
typedef MR_int_least8_t MR_TraceLevelInt;
|
|
|
|
typedef struct MR_Exec_Trace_Struct {
|
|
const MR_Label_Layout *MR_exec_call_label;
|
|
const MR_Module_Layout *MR_exec_module_layout;
|
|
const MR_uint_least8_t *MR_exec_body_bytes;
|
|
MR_TrieNode MR_exec_tabling_pointer;
|
|
MR_Table_Info 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_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_Exec_Trace;
|
|
|
|
#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)
|
|
|
|
#define MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR 0x1
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Proc_Layout
|
|
**
|
|
** Proc layout structures contain one, two or three substructures.
|
|
**
|
|
** - The first substructure is the MR_Stack_Traversal 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_Proc_Id 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_Proc_Id 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 the MR_Exec_Trace and MR_ProcStatic structures, which
|
|
** contain information specifically intended for the debugger and the deep
|
|
** profiler respectively. The MR_Exec_Trace structure will be generated
|
|
** only if the module is compiled with execution tracing, while the
|
|
** MR_ProcStatic structure will be generated only if the module is compiled
|
|
** in a deep profiling grade.
|
|
**
|
|
** The runtime system considers all proc layout structures to be of type
|
|
** MR_Proc_Layout, 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_Proc_Id substructure, MR_PROC_LAYOUT_HAS_EXEC_TRACE to check for the
|
|
** MR_Exec_Trace 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_Exec_Trace substructure will not present, and if the
|
|
** options do not require procedure identification, then the MR_Proc_Id
|
|
** substructure will not be present either
|
|
**
|
|
** 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_Proc_Layout_Traversal.
|
|
**
|
|
** - When generating stack traversal and procedure id information, plus
|
|
** possibly others, the compiler will generate proc layout structures of
|
|
** types MR_Proc_Layout_User and MR_Proc_Layout_UCI.
|
|
*/
|
|
|
|
struct MR_Proc_Layout_Struct {
|
|
MR_Stack_Traversal MR_sle_traversal;
|
|
MR_Proc_Id MR_sle_proc_id;
|
|
MR_STATIC_CODE_CONST MR_Exec_Trace *MR_sle_exec_trace;
|
|
MR_ProcStatic *MR_sle_proc_static;
|
|
};
|
|
|
|
typedef struct MR_Proc_Layout_User_Struct {
|
|
MR_Stack_Traversal MR_user_traversal;
|
|
MR_User_Proc_Id MR_user_id;
|
|
MR_STATIC_CODE_CONST MR_Exec_Trace *MR_sle_exec_trace;
|
|
MR_ProcStatic *MR_sle_proc_static;
|
|
} MR_Proc_Layout_User;
|
|
|
|
typedef struct MR_Proc_Layout_UCI_Struct {
|
|
MR_Stack_Traversal MR_uci_traversal;
|
|
MR_UCI_Proc_Id MR_uci_id;
|
|
MR_STATIC_CODE_CONST MR_Exec_Trace *MR_sle_exec_trace;
|
|
MR_ProcStatic *MR_sle_proc_static;
|
|
} MR_Proc_Layout_UCI;
|
|
|
|
typedef struct MR_Proc_Layout_Traversal_Struct {
|
|
MR_Stack_Traversal MR_trav_traversal;
|
|
MR_Word MR_trav_no_proc_id; /* will be -1 */
|
|
} MR_Proc_Layout_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_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_body_bytes MR_sle_exec_trace->MR_exec_body_bytes
|
|
#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_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_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)
|
|
|
|
/* 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))
|
|
|
|
/*
|
|
** Return the name (if any) of the variable with the given HLDS variable number
|
|
** in the procedure indicated by the first argument.
|
|
*/
|
|
|
|
extern MR_ConstString MR_hlds_var_name(const MR_Proc_Layout *entry,
|
|
int hlds_var_num);
|
|
|
|
/*
|
|
** 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_Proc_Layout *) & \
|
|
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_Proc_Layout_User \
|
|
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_Proc_Layout_UCI \
|
|
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_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(/* extern */, 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(/* extern */, 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(/* extern */, detism, slots,\
|
|
succip_locn, pf, module, name, arity, mode, NULL)
|
|
|
|
#define MR_DECLARE_UCI_PROC_STATIC_LAYOUTS(mod, n, a) \
|
|
const MR_Proc_Layout_UCI \
|
|
MR_proc_layout_uci_name(mod, __Unify__, n, a, 0); \
|
|
const MR_Proc_Layout_UCI \
|
|
MR_proc_layout_uci_name(mod, __Compare__, n, a, 0); \
|
|
const MR_Proc_Layout_UCI \
|
|
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_Module_Layout
|
|
**
|
|
** 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_Trace_Level 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 enum {
|
|
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_NONE),
|
|
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_Trace_Level;
|
|
|
|
typedef struct MR_Module_File_Layout_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_Label_Layout **MR_mfl_label_layout;
|
|
} MR_Module_File_Layout;
|
|
|
|
struct MR_Module_Layout_Struct {
|
|
MR_ConstString MR_ml_name;
|
|
MR_Integer MR_ml_string_table_size;
|
|
const char *MR_ml_string_table;
|
|
MR_Integer MR_ml_proc_count;
|
|
const MR_Proc_Layout **MR_ml_procs;
|
|
MR_Integer MR_ml_filename_count;
|
|
const MR_Module_File_Layout **MR_ml_module_file_layout;
|
|
MR_Trace_Level 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;
|
|
};
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Closure_Id
|
|
**
|
|
** Each closure contains an MR_Closure_Id 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_User_Closure_Id
|
|
** or MR_UCI_Closure_Id structures in order to avoid initializing the
|
|
** MR_Proc_Id union through an inappropriate member.
|
|
*/
|
|
|
|
struct MR_Closure_Id_Struct {
|
|
MR_Proc_Id 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_User_Closure_Id_Struct {
|
|
MR_User_Proc_Id 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_UCI_Closure_Id_Struct {
|
|
MR_UCI_Proc_Id 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 */
|