mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 22:35:41 +00:00
Estimated hours taken: 12
Branches: main
Add a new form of tabling pragma, fast_loose_memo. It differs from memo in
only one way: for arguments of user-defined types, instead of tabling every
single function symbol in the value, it tables a pointer to the term instead.
(Actually, it tables the contents of the selected argument register, so it
works even if the value is not a pointer.)
As the name implies, this form of tabling is faster than memo. The tradeoff
is that it is looser: if two invocations specify two terms that are at
different addresses but have the same value, this new form of tabling will
not recognize the commonality.
doc/reference_manual.texi:
Document the new pragma.
compiler/prog_data.m:
Generalize the type specifying eval methods to allow the expression
of the new form of tabling.
compiler/prog_io_pragma.m:
Parse the new form of tabling pragma.
compiler/hlds_pred.m:
Handle the new, more general form of memoing.
Add the required provisions for the representation of the new form
of trie step in tables.
compiler/table_gen.m:
Implement the new form of tabling as a minor variant of memo tabling.
Convert this module to four-space indentation to reduce the number
of bad line breaks.
compiler/layout_out.m:
compiler/prog_out.m:
Conform to the changes above.
library/table_builtins.m:
Add the primitives required to implement fast_loose_memo.
Fix an old bug: make table_lookup_insert_poly call the right macro.
runtime/mercury_tabling.h:
runtime/mercury_tabling_macros.h:
runtime/mercury_tabling_preds.h:
Provide the basic mechanism of fast_loose_memo tabling: a hash table
that works on MR_Words.
runtime/mercury_stack_layout.h:
Allow the representation of the new evaluation method and the new form
of trie step.
tests/tabling/fast_loose.{m,exp}:
Add this test case of the operation of fast_loose tabling. The test
case pronounces success only if fast_loose_memo is measured to be
significantly faster than plain memo.
tests/tabling/Mmakefile:
Enable the new test case.
1248 lines
50 KiB
C
1248 lines
50 KiB
C
/*
|
|
** Copyright (C) 1998-2005 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. XXX this field is not used yet.
|
|
**
|
|
** 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_LLCCC(e, ln, port, num, path, vc, lt, vn, tv) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, vc, \
|
|
&MR_PASTE2(mercury_common_, lt), \
|
|
&MR_PASTE2(mercury_common_, vn), \
|
|
&MR_PASTE2(mercury_common_, tv))
|
|
|
|
#define MR_DEF_LLCC0(e, ln, port, num, path, vc, lt, vn) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, vc, \
|
|
&MR_PASTE2(mercury_common_, lt), \
|
|
&MR_PASTE2(mercury_common_, vn), 0) \
|
|
|
|
#define MR_DEF_LLTCCC(e, ln, port, num, path, vc, lt, vn, tv) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, vc, \
|
|
&MR_PASTE2(mercury_common_, lt), \
|
|
&MR_PASTE2(mercury_common_, vn), \
|
|
&MR_PASTE2(mercury_common_, tv))
|
|
|
|
#define MR_DEF_LLTCC0(e, ln, port, num, path, vc, lt, vn) \
|
|
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, vc, \
|
|
&MR_PASTE2(mercury_common_, lt), \
|
|
&MR_PASTE2(mercury_common_, vn), 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_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_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_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_Word) entry->MR_sle_user.MR_user_pred_or_func != -1)
|
|
|
|
#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))
|
|
|
|
/*
|
|
** 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.
|
|
** To 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 */
|