Files
mercury/runtime/mercury_stack_layout.h
Zoltan Somogyi 9bdc5db590 Try to work around the Snow Leopard linker's performance problem with
Estimated hours taken: 20
Branches: main

Try to work around the Snow Leopard linker's performance problem with
debug grade object files by greatly reducing the number of symbols needed
to represent the debugger's data structures.

Specifically, this diff groups all label layouts in a module, each of which
previously had its own named global variable, into only a few (one to four)
global variables, each of which is an array. References to the old global
variables are replaced by references to slots in these arrays.

This same treatment could also be applied to other layout structures. However,
most layouts are label layouts, so doing just label layouts gets most of the
available benefit.

When the library and compiler are compiled in grade asm_fast.gc.debug,
this diff leads to about a 1.5% increase in the size of their generated C
source files (from 338 to 343 Mb), but a more significant reduction (about 17%)
in the size of the corresponding object files (from 155 to 128 Mb). This leads
to an overall reduction in disk requirements from 493 to 471 Mb (about 4.5%).
Since we generate the same code and data as before, with the data just being
arranged differently, the decrease in object file sizes is coming from the
reduction in relocation information, the information processed by the linker.
This should speed up the linker.

compiler/layout.m:
	Make the change described above. We now define up to four arrays:
	one each for label layouts with and without information about
	variables, one for the layout structures of user events,
	and one for the variable number lists of user events.

compiler/layout_out.m:
	Generate the new arrays that the module being compiled needs.

	Use purpose-specific types instead of booleans.

compiler/trace_gen.m:
	Use a new field in foreign_proc_code instructions to record the
	identity of any labels whose layout structures we want to refer to,
	even though layout structures have not been generated yet. The labels
	will be looked up in a map (generated together with the layout
	structures) by llds_out.m.

compiler/llds.m:
	Add this extra field to foreign_proc_code instructions.

	Add the map (which is actually in two parts) to the c_file type,
	which is the data structure representing the entire LLDS.

	Also add to the c_file type some other data structures that previously
	we used to hand around alongside it. Some of these data structures
	used to conmingle layout structures that we now separate.

compiler/stack_layout.m:
	Generate array slots instead of separate structures for label layouts.
	Return the different arrays separately.

compiler/llds_out.m:
	Order the output of layout structures to require fewer forward
	declarations. The forward declarations of the few arrays holding the
	label layout structures replace a lot of the declarations previously
	needed.

	Include the information needed by layout_out.m in the llds_out_info,
	and conform to the changes above.

	As a side-effect of all these changes, we now generate proc layout
	structures in the same order as the procedures' appearence in the HLDS,
	which is the same as their order in the source code, modulo any
	procedures added by the compiler itself (for lambdas, unification
	predicates, etc).

compiler/code_info.m:
compiler/dupelim.m:
compiler/dup_proc.m:
compiler/exprn_aux.m:
compiler/frameopt.m:
compiler/global_data.m:
compiler/ite_gen.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_to_x86_64.m:
compiler/mercury_compile_llds_back_end.m:
compiler/middle_rec.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/pragma_c_gen.m:
compiler/proc_gen.m:
compiler/reassign.m:
compiler/use_local_vars.m:
	Conform to the changes above.

runtime/mercury_goto.h:
	Add the macros used by the new code in layout_out.m and llds_out.m.
	We need new macros because the old ones assumed that the
	C preprocessor can construct the address of a label's layout structure
	from the name of the label, which is obviously no longer possible.

	Make even existing families of macros handle in bulk up to 10 labels,
	up from the previous 8.

runtime/mercury_stack_layout.h:
	Add macros for use by the new code in layout.m.

tests/debugger/*.{inp,exp}:
tests/debugger/declarative/*.{inp,exp}:
	Update these test cases to account for the new (and better) order
	of proc layout structures. Where inputs changed, this was to ensure
	that we still select the same procedures from lists of procedures,
	e.g. to put a breakpoint on.
2009-10-21 06:36:37 +00:00

1572 lines
77 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1998-2009 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
#ifndef MERCURY_STACK_LAYOUT_H
#define MERCURY_STACK_LAYOUT_H
/*
** mercury_stack_layout.h -
**
** Definitions for stack layout data structures. These are generated by the
** compiler, and are used by the parts of the runtime system that need to look
** at the stacks (and sometimes the registers) and make sense of their
** contents. The parts of the runtime system that need to do this include
** exception handling, the debugger, and (eventually) the accurate garbage
** collector.
**
** For a general description of the idea of stack layouts, see the paper
** "Run time type information in Mercury" by Tyson Dowd, Zoltan Somogyi,
** Fergus Henderson, Thomas Conway and David Jeffery, which is available from
** the Mercury web site. The relevant section is section 3.8, but be warned:
** while the general principles remain applicable, the details have changed
** since that paper was written.
**
** NOTE: The constants and data-structures used here need to be kept in
** sync with the ones generated in the compiler. If you change anything here,
** you may need to change stack_layout.m, layout.m, and/or layout_out.m in
** the compiler directory as well.
*/
#include "mercury_types.h"
#include "mercury_std.h" /* for MR_VARIABLE_SIZED */
#include "mercury_tags.h"
#include "mercury_type_info.h" /* for MR_PseudoTypeInfo */
#include "mercury_proc_id.h" /* for MR_ProcId */
#include "mercury_goto.h" /* for MR_PROC_LAYOUT etc */
#include "mercury_tabling.h" /* for MR_TableTrieStep etc */
#include "mercury_bootstrap.h" /* for MR_Table_Trie_Step */
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_Determinism
*/
/*
** The max_soln component of the determinism is encoded in the 1 and 2 bits.
** The can_fail component of the determinism is encoded in the 4 bit.
** The first_solution component of the determinism is encoded in the 8 bit.
**
** MR_DETISM_AT_MOST_MANY could also be defined as ((d) & 3) == 3),
** but this would be less efficient, since the C compiler does not know
** that we do not set the 1 bit unless we also set the 2 bit.
**
** NOTE: this must match the encoding specified by represent_determinism/1
** in mdbcomp/program_representation.m.
*/
typedef MR_int_least16_t MR_Determinism;
#define MR_DETISM_DET 6
#define MR_DETISM_SEMI 2
#define MR_DETISM_NON 3
#define MR_DETISM_MULTI 7
#define MR_DETISM_ERRONEOUS 4
#define MR_DETISM_FAILURE 0
#define MR_DETISM_CCNON 10
#define MR_DETISM_CCMULTI 14
#define MR_DETISM_MAX 14
#define MR_DETISM_AT_MOST_ZERO(d) (((d) & 3) == 0)
#define MR_DETISM_AT_MOST_ONE(d) (((d) & 3) == 2)
#define MR_DETISM_AT_MOST_MANY(d) (((d) & 1) != 0)
#define MR_DETISM_CAN_FAIL(d) (((d) & 4) == 0)
#define MR_DETISM_FIRST_SOLN(d) (((d) & 8) != 0)
#define MR_DETISM_DET_STACK(d) (!MR_DETISM_AT_MOST_MANY(d) \
|| MR_DETISM_FIRST_SOLN(d))
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_LongLval and MR_ShortLval
*/
/*
** MR_LongLval is a MR_Unsigned which describes a location.
** This includes lvals such as stack slots, general registers, and special
** registers such as succip, hp, etc, as well as locations whose address is
** given as a typeinfo inside the type class info structure pointed to by an
** lval.
**
** What kind of location an MR_LongLval refers to is encoded using
** a low tag with MR_LONG_LVAL_TAGBITS bits; the type MR_LongLvalType
** describes the different tag values. The interpretation of the rest of
** the word depends on the location type:
**
** Locn Rest
**
** MR_r(Num) Num (register number)
** MR_f(Num) Num (register number)
** MR_stackvar(Num) Num (stack slot number)
** MR_framevar(Num) Num (stack slot number)
** MR_succip
** MR_maxfr
** MR_curfr
** MR_hp
** MR_sp
** constant See below
** indirect(Base, N) See below
** unknown (The location is not known)
**
** For constants, the rest of the word is a pointer to static data. The
** pointer has only two low tag bits free, so we reserve every four-bit tag
** which has 00 as its bottom two bits for representing them.
**
** For indirect references, the word exclusive of the tag consists of
** (a) an integer with MR_LONG_LVAL_OFFSETBITS bits giving the index of
** the typeinfo inside a type class info (to be interpreted by
** MR_typeclass_info_type_info or the predicate
** private_builtin:type_info_from_typeclass_info, which calls it) and
** (b) a MR_LongLval value giving the location of the pointer to the
** type class info. This MR_LongLval value will *not* have an indirect
** tag.
**
** This data is generated in stack_layout.represent_locn_as_int,
** which must be kept in sync with the constants and macros defined here.
*/
struct MR_LongLval_Struct {
MR_Unsigned MR_long_lval;
};
typedef enum {
MR_LONG_LVAL_TYPE_CONS_0,
MR_LONG_LVAL_TYPE_R,
MR_LONG_LVAL_TYPE_F,
MR_LONG_LVAL_TYPE_STACKVAR,
MR_LONG_LVAL_TYPE_CONS_1,
MR_LONG_LVAL_TYPE_FRAMEVAR,
MR_LONG_LVAL_TYPE_SUCCIP,
MR_LONG_LVAL_TYPE_MAXFR,
MR_LONG_LVAL_TYPE_CONS_2,
MR_LONG_LVAL_TYPE_CURFR,
MR_LONG_LVAL_TYPE_HP,
MR_LONG_LVAL_TYPE_SP,
MR_LONG_LVAL_TYPE_CONS_3,
MR_LONG_LVAL_TYPE_INDIRECT,
MR_LONG_LVAL_TYPE_UNKNOWN
} MR_LongLvalType;
/* This must be in sync with stack_layout.long_lval_tag_bits */
#define MR_LONG_LVAL_TAGBITS 4
#define MR_LONG_LVAL_CONST_TAGBITS 2
#define MR_LONG_LVAL_TYPE(Locn) \
((MR_LongLvalType) \
((Locn).MR_long_lval & ((1 << MR_LONG_LVAL_TAGBITS) - 1)))
#define MR_LONG_LVAL_NUMBER(Locn) \
((int) (Locn).MR_long_lval >> MR_LONG_LVAL_TAGBITS)
#define MR_LONG_LVAL_CONST(Locn) \
(* (MR_Word *) ((Locn).MR_long_lval & \
~ ((1 << MR_LONG_LVAL_CONST_TAGBITS) - 1)))
/* This must be in sync with stack_layout.offset_bits */
#define MR_LONG_LVAL_OFFSETBITS 6
#define MR_LONG_LVAL_INDIRECT_OFFSET(LocnNumber) \
((int) ((LocnNumber).MR_long_lval & \
((1 << MR_LONG_LVAL_OFFSETBITS) - 1)))
#define MR_LONG_LVAL_INDIRECT_BASE_LVAL_INT(LocnNumber) \
(((MR_uint_least32_t) (LocnNumber).MR_long_lval) \
>> MR_LONG_LVAL_OFFSETBITS)
#define MR_LONG_LVAL_STACKVAR_INT(n) \
(((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_STACKVAR)
#define MR_LONG_LVAL_FRAMEVAR_INT(n) \
(((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_FRAMEVAR)
#define MR_LONG_LVAL_R_REG_INT(n) \
(((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_R)
/*
** MR_ShortLval is a MR_uint_least8_t which describes an location. This
** includes lvals such as stack slots and general registers that have small
** numbers, and special registers such as succip, hp, etc.
**
** What kind of location an MR_LongLval refers to is encoded using
** a low tag with 2 bits; the type MR_ShortLval_Type describes
** the different tag values. The interpretation of the rest of the word
** depends on the location type:
**
** Locn Tag Rest
** MR_r(Num) 0 Num (register number)
** MR_stackvar(Num) 1 Num (stack slot number)
** MR_framevar(Num) 2 Num (stack slot number)
** special reg 3 MR_LongLvalType
**
** This data is generated in stack_layout.represent_locn_as_byte,
** which must be kept in sync with the constants and macros defined here.
*/
typedef MR_uint_least8_t MR_ShortLval;
typedef enum {
MR_SHORT_LVAL_TYPE_R,
MR_SHORT_LVAL_TYPE_STACKVAR,
MR_SHORT_LVAL_TYPE_FRAMEVAR,
MR_SHORT_LVAL_TYPE_SPECIAL
} MR_ShortLval_Type;
/* This must be in sync with stack_layout.short_lval_tag_bits */
#define MR_SHORT_LVAL_TAGBITS 2
#define MR_SHORT_LVAL_TYPE(Locn) \
((MR_ShortLval_Type) \
(((MR_Word) Locn) & ((1 << MR_SHORT_LVAL_TAGBITS) - 1)))
#define MR_SHORT_LVAL_NUMBER(Locn) \
((int) ((MR_Word) Locn) >> MR_SHORT_LVAL_TAGBITS)
#define MR_SHORT_LVAL_STACKVAR(n) \
((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS) \
+ MR_SHORT_LVAL_TYPE_STACKVAR))
#define MR_SHORT_LVAL_FRAMEVAR(n) \
((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS) \
+ MR_SHORT_LVAL_TYPE_FRAMEVAR))
#define MR_SHORT_LVAL_R_REG(n) \
((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS) \
+ MR_SHORT_LVAL_TYPE_R))
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_UserEvent and MR_UserEventSpec
*/
/*
** Our layout structures link to information about user events from two places:
** the label layout structures of labels that correspond to user events,
** and the module layout structures of modules that contain user events.
** Label layout structures link to MR_UserEvent structures; module layout
** structures link to MR_UserEventSpec structures. Most of the information
** is in the MR_UserEventSpec structures; MR_UserEvent structures contain
** only information that may differ between two instances of the same event.
*/
/*
** The fields of MR_UserEvent:
**
** The event_number field contains the ordinal number of the event in the
** event set the module was compiled with: it gives the identity of the event.
** (Event numbers start at zero.) This field is also the link to the rest of
** the information about the event, contained in the MR_UserEventSpec structure
** linked to by the module layout structure. The MR_user_event_spec macro
** follows this link.
**
** The next two fields all point to arrays whose length is the number of
** attributes (which is available in the MR_UserEventSpec structure).
**
** attr_locns[i] gives the location where we can find the value of the
** i'th attribute (the first attribute is attribute zero). This is
** meaningful only if the attribute is not a synthesized attribute.
**
** attr_var_nums[i] gives the variable number of the i'th attribute;
** if it contains zero, that means the attribute is synthesized. This field
** is used by the debugger to display the associated value just once
** (not twice, as both attribute and variable value) with "print *". (Note
** that we don't delete the variables that are also attributes from the set of
** live variables in layout structures, because that would require any native
** garbage collector to look at the list of attributes as well as the list of
** other variables, slowing it down.)
*/
typedef MR_uint_least16_t MR_HLDSVarNum;
struct MR_UserEvent_Struct {
MR_uint_least16_t MR_ue_event_number;
MR_LongLval *MR_ue_attr_locns;
const MR_HLDSVarNum *MR_ue_attr_var_nums;
};
/*
** The fields of MR_UserEventSpec:
**
** The event_name field contains the name of the event.
**
** The num_attrs field gives the number of attributes.
**
** The next three fields (attr_names, attr_types and synth_attrs) all point
** to arrays whose length is the number of attributes.
**
** attr_names[i] gives the name of the i'th attribute.
**
** attr_types[i] is the typeinfo giving the type of the i'th attribute.
**
** If the i'th attribute is synthesized, synth_attrs[i] points to the
** information required to synthesize it: the number of the attribute
** containing the synthesis function, the number of arguments of the synthesis
** function, and an array of attribute numbers (of length num_arg_attrs)
** giving the list of those arguments. The depend_attrs field will point to
** a list of numbers of the synthesized attributes whose values must be
** materialized before this attribute can be evaluated. (This list will include
** the argument attributes, and will be in a feasible evaluation order.)
** If the i'th attribute is not synthesized, synth_attrs[i] and depend_attrs[i]
** will both be NULL. (For now, depend_attrs[i] will not be filled in for
** synthesized attributes either.)
**
** The synth_attr_order field points to an array of attribute numbers that
** gives the order in which the values of the synthesized attributes should be
** evaluated. The array is ended by -1 as a sentinel.
**
** The synth_attrs and synth_attr_order fields will both be NULL for events
** that have no synthesized attributes.
*/
struct MR_SynthAttr_Struct {
MR_int_least16_t MR_sa_func_attr;
MR_int_least16_t MR_sa_num_arg_attrs;
MR_uint_least16_t *MR_sa_arg_attrs;
MR_int_least16_t *MR_sa_depend_attrs;
};
struct MR_UserEventSpec_Struct {
const char *MR_ues_event_name;
MR_uint_least16_t MR_ues_num_attrs;
const char **MR_ues_attr_names;
MR_TypeInfo *MR_ues_attr_types;
MR_SynthAttr *MR_ues_synth_attrs;
MR_int_least16_t *MR_ues_synth_attr_order;
};
#define MR_user_event_spec(label_layout) \
label_layout->MR_sll_entry->MR_sle_module_layout-> \
MR_ml_user_event_specs[label_layout->MR_sll_user_event-> \
MR_ue_event_number]
#define MR_user_event_set_name(label_layout) \
label_layout->MR_sll_entry->MR_sle_module_layout-> \
MR_ml_user_event_set_name
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_LabelLayout
*/
/*
** An MR_LabelLayout structure describes the debugging and accurate gc
** information available at a given label.
**
** The MR_sll_entry field points to the proc layout structure of the procedure
** in which the label occurs.
**
** The MR_sll_port field will contain a negative number if there is no
** execution tracing port associated with the label. If there is, the
** field will contain a value of type MR_TracePort. For labels associated
** with events, this will be the port of the event. For return labels,
** this port will be exception (since exception events are associated with
** the return from the call that raised the exception).
**
** The MR_sll_hidden field contains a boolean which is meaningful only if the
** label corresponds to an execution tracing event. It will be MR_HIDDEN if the
** event should have no effects that the user can see (no message printed, no
** increment of the event number etc), and MR_NOT_HIDDEN otherwise. Hidden
** events are sometimes needed by the declarative debugger to provide the
** proper context for other events.
**
** The MR_sll_goal_path field contains an offset into the module-wide string
** table, leading to a string that gives the goal path associated with the
** label. If there is no meaningful goal path associated with the label,
** the offset will be zero, leading to the empty string. You can use the macro
** MR_label_goal_path to convert the value in the MR_sll_goal_path field to a
** string.
**
** If the label is the label of a user-defined event, then the
** MR_sll_user_event field will point to information about the user event;
** otherwise, the field will be NULL.
**
** The remaining fields give information about the values live at the given
** label, if this information is available. If it is available, the
** MR_has_valid_var_count macro will return true and the 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_LabelLayoutNoVarInfo structure).
**
** The format in which we store information about the values live at the label
** is somewhat complicated, due to our desire to make this information compact.
** We can represent a location in one of two ways, as an 8-bit MR_ShortLval
** or as a 32-bit MR_LongLval. We prefer representing a location as an
** MR_ShortLval, but of course not all locations can be represented in
** this way, so those other locations are represented as MR_LongLvals.
**
** The MR_sll_var_count field, if it is valid, is encoded by the formula
** (#Long << MR_SHORT_COUNT_BITS + #Short), where #Short is the number
** data items whose descriptions fit into an MR_ShortLval and #Long is the
** number of data items whose descriptions do not. (The number of distinct
** values that fit into 8 bits also fits into 8 bits, but since some
** locations hold the value of more than one variable at a time, not all
** the values need to be distinct; this is why MR_SHORT_COUNT_BITS is
** more than 8.)
**
** The MR_sll_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_LongLvals, and the third is an array of
** #Short MR_ShortLvals, 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_TypeParamLocns structure that gives the locations of the
** typeinfos for those type variables. This structure gives the number of type
** variables and their locations, so that the code that needs the type
** parameters can materialize all the type parameters from their location
** descriptions in one go. This is an optimization, since the type parameter
** vector could simply be indexed on demand by the type variable's variable
** number stored within the MR_PseudoTypeInfos stored inside the 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
** correspond to an event.
**
** XXX: Presently, inst information is ignored; we assume that all live values
** are ground.
*/
#define MR_HIDDEN 1
#define MR_NOT_HIDDEN 0
struct MR_TypeParamLocns_Struct {
MR_uint_least32_t MR_tp_param_count;
MR_LongLval MR_tp_param_locns[MR_VARIABLE_SIZED];
};
struct MR_LabelLayout_Struct {
const MR_ProcLayout *MR_sll_entry;
MR_int_least8_t MR_sll_port;
MR_int_least8_t MR_sll_hidden;
MR_uint_least16_t MR_sll_label_num_in_module;
MR_uint_least32_t MR_sll_goal_path;
const MR_UserEvent *MR_sll_user_event;
MR_Integer MR_sll_var_count; /* >= 0 */
const void *MR_sll_locns_types;
const MR_HLDSVarNum *MR_sll_var_nums;
const MR_TypeParamLocns *MR_sll_tvars;
};
typedef struct MR_LabelLayoutNoVarInfo_Struct {
const MR_ProcLayout *MR_sll_entry;
MR_int_least8_t MR_sll_port;
MR_int_least8_t MR_sll_hidden;
MR_uint_least16_t MR_sll_label_num_in_module;
MR_uint_least32_t MR_sll_goal_path;
const MR_UserEvent *MR_sll_user_event;
MR_Integer MR_sll_var_count; /* < 0 */
} MR_LabelLayoutNoVarInfo;
#define MR_label_goal_path(layout) \
((MR_PROC_LAYOUT_HAS_EXEC_TRACE((layout)->MR_sll_entry)) ? \
((layout)->MR_sll_entry->MR_sle_module_layout \
->MR_ml_string_table \
+ (layout)->MR_sll_goal_path) \
: "")
#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_LongLval *) 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_ShortLval *) \
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_LabelLayout *) &MR_LAYOUT_FROM_LABEL(MR_add_prefix(label)))
#define MR_MAKE_USER_INTERNAL_LAYOUT(module, name, arity, mode, label) \
MR_LabelLayoutNoVarInfo \
MR_label_layout_user_name(module, name, arity, mode, label) = { \
(MR_ProcLayout *) & \
MR_proc_layout_user_name(module, name, arity, mode), \
0, \
-1, \
MR_FALSE, \
0, \
0, \
-1 /* No info about live values */ \
}
/*-------------------------------------------------------------------------*/
/*
** These macros are used as shorthands in generated C source files.
** The first two arguments are the entry label name and the label number;
** the others are the fields of MR_LabelLayouts.
*/
#define MR_DEF_LL_GEN(e, ln, port, h, num, path, ue, vc, lt, vn, tv) \
static const MR_LabelLayout \
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), (ue), (vc), \
((const void *) lt), \
((const MR_uint_least16_t *) vn), \
((const MR_TypeParamLocns *) tv) \
}
#define MR_DEF_LLNVI_GEN(e, ln, port, h, num, path, ue) \
static const MR_LabelLayoutNoVarInfo \
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), (ue), -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, NULL, 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, NULL, vc, lt, vn, tv)
#define MR_DEF_LL_U(e, ln, port, num, path, vc, lt, vn, tv) \
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)), \
vc, lt, vn, tv)
#define MR_DEF_LLT_U(e, ln, port, num, path, vc, lt, vn, tv) \
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)), \
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, NULL, 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, NULL, 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, NULL, 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, NULL, vc, \
MR_XCOMMON(ltt, ltc), \
MR_XCOMMON(vnt, vnc), 0)
#define MR_DEF_LLXCCC_U(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc, tvt, tvc)\
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)), \
vc, \
MR_XCOMMON(ltt, ltc), \
MR_XCOMMON(vnt, vnc), \
MR_XCOMMON(tvt, tvc))
#define MR_DEF_LLXCC0_U(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc) \
MR_DEF_LL_GEN(e, ln, port, MR_FALSE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)), \
vc, \
MR_XCOMMON(ltt, ltc), \
MR_XCOMMON(vnt, vnc), 0)
#define MR_DEF_LLTXCCC_U(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc, tvt,tvc)\
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)), \
vc, \
MR_XCOMMON(ltt, ltc), \
MR_XCOMMON(vnt, vnc), \
MR_XCOMMON(tvt, tvc))
#define MR_DEF_LLTXCC0_U(e, ln, port, num, path, vc, ltt, ltc, vnt, vnc) \
MR_DEF_LL_GEN(e, ln, port, MR_TRUE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)), \
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, NULL)
#define MR_DEF_LLNVIT(e, ln, port, num, path) \
MR_DEF_LLNVI_GEN(e, ln, port, MR_TRUE, path, NULL)
#define MR_DEF_LLNVI_U(e, ln, port, num, path) \
MR_DEF_LLNVI_GEN(e, ln, port, MR_FALSE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)))
#define MR_DEF_LLNVIT_U(e, ln, port, num, path) \
MR_DEF_LLNVI_GEN(e, ln, port, MR_TRUE, num, path, \
&MR_USER_LAYOUT_NAME(MR_label_name(MR_add_prefix(e), ln)))
/*-------------------------------------------------------------------------*/
#define MR_DECL_LL(e, ln) \
MR_declare_label(MR_label_name(MR_add_prefix(e), ln)); \
static const MR_LabelLayout \
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_LabelLayoutNoVarInfo \
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)
/*-------------------------------------------------------------------------*/
/*
** These macros are used as shorthands in generated C source files
** for some fields of MR_LabelLayouts.
**
** We need to cast the addresses of proc layout structures because there
** are several kinds of proc layouts, of different (though compatible) types.
**
** We need to cast the values we intend to put into the MR_sll_locns_types,
** MR_sll_var_nums and MR_sll_tvars field because (due to our representation
** scheme, documented with the MR_LabelLayout type) the values supplied by
** the compiler will usually be references to slots in arrays of data-specific
** types.
*/
#define MR_LLC(e, port, num, path) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_NOT_HIDDEN, (num), (path), NULL
#define MR_LLC_H(e, port, num, path) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_HIDDEN, (num), (path), NULL
#define MR_LLC_U(e, port, num, path, ue) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_NOT_HIDDEN, (num), (path), (ue)
#define MR_LLC_H_U(e, port, num, path, ue) \
MR_PROC_LAYOUT(MR_add_prefix(e)), \
MR_PASTE2(MR_PORT_, port), \
MR_HIDDEN, (num), (path), (ue)
#define MR_LLV(lt, vn, tp) \
(const void *) (lt), \
(const MR_uint_least16_t *) (vn), \
(const MR_TypeParamLocns *) (tp)
#define MR_LLV_CC(ltt, ltc, vnt, vnc, tp) \
(const void *) MR_XCOMMON(ltt, ltc), \
(const MR_uint_least16_t *) MR_XCOMMON(vnt, vnc), \
(const MR_TypeParamLocns *) (tp)
#define MR_LLV_CCC(ltt, ltc, vnt, vnc, tpt, tpc) \
(const void *) MR_XCOMMON(ltt, ltc), \
(const MR_uint_least16_t *) MR_XCOMMON(vnt, vnc), \
(const MR_TypeParamLocns *) MR_XCOMMON(tpt, tpc)
#define MR_LLV_CC0(ltt, ltc, vnt, vnc) \
(const void *) MR_XCOMMON(ltt, ltc), \
(const MR_uint_least16_t *) MR_XCOMMON(vnt, vnc), \
(const MR_TypeParamLocns *) 0
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ProcLayout
*/
/*
** The MR_TableIoDecl structure.
**
** To enable declarative debugging of I/O actions, the compiler generates one
** of these structures for each I/O primitive. The compiler transforms the
** bodies of those primitives to create a block of memory and fill it in with
** (1) a pointer to the primitive's MR_TableIoDecl structure and (2) the
** values of the primitive's arguments (both input and output, but excluding
** the I/O states). The array of pseudo-typeinfos pointed to by the ptis field
** gives the types of these arguments, while the filtered_arity field gives
** the number of saved arguments, which will be all the arguments except the
** I/O states. The number in this field is the size of the ptis array, and
** the size of the block exclusive of the pointer. The proc field allows us
** to identify the primitive procedure. This is all the information we need
** to describe the I/O action to the user.
*/
typedef struct MR_TableIoDecl_Struct {
const MR_ProcLayout *MR_table_io_decl_proc;
MR_Integer MR_table_io_decl_filtered_arity;
const MR_PseudoTypeInfo *MR_table_io_decl_ptis;
const MR_TypeParamLocns *MR_table_io_decl_type_params;
} MR_TableIoDecl;
/*
** MR_TableInfo: compiler generated information describing the tabling
** data structures used by a procedure.
**
** For I/O tabled procedures, the information is in the io_decl field.
** For other kinds of tabled procedures, it is in the gen field.
** The init field is used for initialization only.
**
** The MR_table_proc field is not const because the structure it points to
** has fields containing statistics, which are updated at runtime.
*/
typedef union {
const void *MR_table_init;
const MR_TableIoDecl *MR_table_io_decl;
const MR_Table_Gen *MR_table_gen;
MR_ProcTableInfo *MR_table_proc;
} MR_TableInfo;
/*
** The MR_StackTraversal structure contains the following fields:
**
** The code_addr field points to the start of the procedure's code.
** This allows the profiler to figure out which procedure a sampled program
** counter belongs to, and allows the debugger to implement retry.
**
** The succip_locn field encodes the location of the saved succip if it is
** saved in a general purpose stack slot. If the succip is saved in a special
** purpose stack slot (as it is for model_non procedures) or if the procedure
** never saves the succip (as in leaf procedures), this field will contain -1.
**
** The stack_slots field gives the number of general purpose stack slots
** in the procedure.
**
** The detism field encodes the determinism of the procedure.
*/
typedef struct MR_StackTraversal_Struct {
MR_Code *MR_trav_code_addr;
MR_LongLval MR_trav_succip_locn;
MR_int_least16_t MR_trav_stack_slots;
MR_Determinism MR_trav_detism;
} MR_StackTraversal;
#define MR_PROC_LAYOUT_IS_UCI(entry) \
MR_PROC_ID_IS_UCI(entry->MR_sle_proc_id)
/*
** The MR_ExecTrace structure contains the following fields.
**
** The call_label field points to the label layout structure for the label
** associated with the call event at the entry to the procedure. The purpose
** of this field is to allow the debugger to find out which variables
** are where on entry, so it can reexecute the procedure if asked to do so
** and if the values of the required variables are still available.
**
** The labels field contains a pointer to an array of pointers to label layout
** structures; the size of the array is given by the num_labels field. The
** initial part of the array will contain a pointer to the label layout
** structure of every interface event in the procedure; the later parts will
** contain a pointer to the label layout structure of every internal event.
** There is no ordering on the events beyond interface first, internal second.
**
** The used_var_names field points to an array that contains offsets
** into the string table, with the offset at index i-1 giving the name of
** variable i (since variable numbers start at one). If a variable has no name
** or cannot be referred to from an event, the offset will be zero, at which
** offset the string table will contain an empty string.
**
** The max_named_var_num field gives the number of elements in the
** used_var_names table, which is also the number of the highest numbered
** named variable. Note that unnamed variables may have numbers higher than
** this.
**
** The max_r_num field tells the debugger which Mercury abstract machine
** registers need saving in MR_trace: besides the special registers, it is
** the general-purpose registers rN for values of N up to and including the
** value of this field. Note that this field contains an upper bound; in
** general, there will be calls to MR_trace at which the number of the highest
** numbered general purpose (i.e. rN) registers is less than this. However,
** storing the upper bound gets us almost all the benefit (of not saving and
** restoring all the thousand rN registers) for a small fraction of the static
** space cost of storing the actual number in label layout structures.
**
** If the procedure is compiled with deep tracing, the maybe_from_full field
** will contain a negative number. If it is compiled with shallow tracing,
** it will contain the number of the stack slot that holds the flag that says
** whether this incarnation of the procedure was called from deeply traced code
** or not. (The determinism of the procedure decides whether the stack slot
** refers to a stackvar or a framevar.)
**
** If tabling of I/O actions is enabled, the maybe_io_seq field will contain
** the number of the stack slot that holds the value the I/O action counter
** had on entry to this procedure. Even procedures that do not have I/O state
** arguments will have such a slot, since they or their descendants may call
** unsafe_perform_io.
**
** If trailing is not enabled, the maybe_trail field will contain a negative
** number. If it is enabled, it will contain number of the first of two stack
** slots used for checkpointing the state of the trail on entry to the
** procedure. The first contains the trail pointer, the second the ticket.
**
** If the procedure lives on the nondet stack, or if it cannot create any
** temporary nondet stack frames, the maybe_maxfr field will contain a negative
** number. If it lives on the det stack, and can create temporary nondet stack
** frames, it will contain the number number of the stack slot that contains the
** value of maxfr on entry, for use in executing the retry debugger command
** from the middle of the procedure.
**
** The eval_method field contains a representation of the evaluation method
** used by the procedure. The retry command needs this information if it is
** to reset the call tables of the procedure invocations being retried.
**
** We cannot put enums into structures as bit fields. To avoid wasting space,
** we put MR_EvalMethodInts into structures instead of MR_EvalMethods
** themselves.
**
** If the procedure is compiled with some form of tabling, the maybe_call_table
** field contains the number of the stack slot through which we can reach the
** call table entry for this call. In forms of tabling which associate a C
** structure (MR_Subgoal, MR_MemoNonRecord) with a call table entry, the slot
** will point to that structure; in other forms of tabling, it will point
** to the call's MR_TableNode.
**
** The flags field encodes boolean properties of the procedure. For now,
** the only property is whether the procedure has a pair of I/O state
** arguments.
**
** If the procedure lives on the nondet stack, or if it cannot create any
** temporary nondet stack frames, the maybe_maxfr field will contain a negative
** number. If it lives on the det stack, and can create temporary nondet stack
** frames, it will contain the number of the stack slot that contains the
** value of maxfr on entry, for use in executing the retry debugger command
** from the middle of the procedure.
*/
#define MR_EVAL_METHOD_MEMO_STRICT MR_EVAL_METHOD_MEMO
#define MR_EVAL_METHOD_MEMO_FAST_LOOSE MR_EVAL_METHOD_MEMO
#define MR_EVAL_METHOD_MEMO_SPECIFIED MR_EVAL_METHOD_MEMO
typedef enum {
MR_EVAL_METHOD_NORMAL,
MR_EVAL_METHOD_LOOP_CHECK,
MR_EVAL_METHOD_MEMO,
MR_EVAL_METHOD_MINIMAL_STACK_COPY,
MR_EVAL_METHOD_MINIMAL_OWN_STACKS_CONSUMER,
MR_EVAL_METHOD_MINIMAL_OWN_STACKS_GENERATOR,
MR_EVAL_METHOD_TABLE_IO,
MR_EVAL_METHOD_TABLE_IO_DECL,
MR_EVAL_METHOD_TABLE_IO_UNITIZE,
MR_EVAL_METHOD_TABLE_IO_UNITIZE_DECL
} MR_EvalMethod;
typedef MR_int_least8_t MR_EvalMethodInt;
typedef enum {
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_NONE),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_BASIC),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_BASIC_USER),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_SHALLOW),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_DEEP),
MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_DECL_REP)
} MR_TraceLevel;
typedef MR_int_least8_t MR_TraceLevelInt;
typedef struct MR_ExecTrace_Struct {
const MR_LabelLayout *MR_exec_call_label;
const MR_ModuleLayout *MR_exec_module_layout;
const MR_LabelLayout **MR_exec_labels;
MR_uint_least32_t MR_exec_num_labels;
MR_TableInfo MR_exec_table_info;
const MR_uint_least16_t *MR_exec_head_var_nums;
const MR_uint_least32_t *MR_exec_used_var_names;
MR_uint_least16_t MR_exec_num_head_vars;
MR_uint_least16_t MR_exec_max_named_var_num;
MR_uint_least16_t MR_exec_max_r_num;
MR_int_least8_t MR_exec_maybe_from_full;
MR_int_least8_t MR_exec_maybe_io_seq;
MR_int_least8_t MR_exec_maybe_trail;
MR_int_least8_t MR_exec_maybe_maxfr;
MR_EvalMethodInt MR_exec_eval_method_CAST_ME;
MR_int_least8_t MR_exec_maybe_call_table;
MR_TraceLevelInt MR_exec_trace_level_CAST_ME;
MR_uint_least8_t MR_exec_flags;
MR_int_least8_t MR_exec_maybe_tail_rec;
} MR_ExecTrace;
#define MR_compute_max_mr_num(max_mr_num, layout) \
do { \
int max_r_num; \
\
max_r_num = (layout)->MR_sll_entry->MR_sle_max_r_num + \
MR_NUM_SPECIAL_REG; \
max_mr_num = MR_max(max_r_num, MR_FIRST_UNREAL_R_SLOT); \
} while (0)
#define MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR 0x1
#define MR_trace_find_reused_frames(proc_layout, sp, reused_frames) \
do { \
const MR_ExecTrace *exec_trace; \
int tailrec_slot; \
\
exec_trace = proc_layout->MR_sle_exec_trace; \
if (exec_trace == NULL) { \
(reused_frames) = 0; \
} else { \
tailrec_slot = proc_layout->MR_sle_maybe_tailrec; \
if (tailrec_slot <= 0) { \
(reused_frames) = 0; \
} else { \
if (MR_DETISM_DET_STACK(proc_layout->MR_sle_detism)) { \
(reused_frames) = MR_based_stackvar((sp), tailrec_slot);\
} else { \
MR_fatal_error("tailrec reuses nondet stack frames"); \
} \
} \
} \
} while (0)
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ProcLayout
**
** Proc layout structures contain one, two or three substructures.
**
** - The first substructure is the MR_StackTraversal structure, which contains
** information that enables the stack to be traversed, e.g. for accurate gc.
** It is always present if proc layouts are present at all.
**
** - The second group is the MR_ProcId union, which identifies the
** procedure in terms that are meaningful to both humans and machines.
** It will be generated only if the module is compiled with stack tracing,
** execution tracing or profiling. The MR_ProcId union has two alternatives,
** one for user-defined procedures and one for procedures of the compiler
** generated Unify, Index and Compare predicates.
**
** - The third group is everything else. Currently, this consists of
** information that is of interest to the debugger, to the deep profiler,
** or both.
**
** The information that is of interest to the debugger only is stored in
** the MR_ExecTrace structure, which will be generated only if the module
** is compiled with execution tracing. The information that is of interest to
** the deep profiler is stored in the MR_ProcStatic structure, which will be
** generated only if the module is compiled in a deep profiling grade. The
** other fields in the group are of interest to both the debugger and the
** deep profiler, and will be generated if either execution tracing or deep
** profiling is enabled.
**
** If the body_bytes field is NULL, it means that no representation of the
** procedure body is available. If non-NULL, it contains a pointer to an
** array of bytecodes that represents the body of the procedure. The
** bytecode array should be interpreted by the read_proc_rep predicate in
** browser/declarative_execution.m (it starts with an encoded form of the
** array's length).
**
** The module_common_layout field points to the part of the module layout
** structure of the module containing the procedure that is common to the
** debugger and the deep profiler. Amongst other things, it gives access to
** the string table that the body_bytes fields refers to.
**
** The runtime system considers all proc layout structures to be of type
** MR_ProcLayout, but must use the macros defined below to check for the
** existence of each substructure before accessing the fields of that
** substructure. The macros are MR_PROC_LAYOUT_HAS_PROC_ID to check for the
** MR_ProcId substructure, MR_PROC_LAYOUT_HAS_EXEC_TRACE to check for the
** MR_ExecTrace substructure, and MR_PROC_LAYOUT_HAS_PROC_STATIC to check for
** the MR_ProcStatic substructure.
**
** The reason why some substructures may be missing is to save space.
** If the options with which a module is compiled do not require execution
** tracing, then the MR_ExecTrace substructure will not present, and if the
** options do not require procedure identification, then the MR_ProcId
** substructure will not be present either. The body_bytes and module_layout
** fields cannot be non-NULL unless at least one of exec trace and proc static
** substructures is present, but they are otherwise independent of those
** substructures.
**
** The compiler itself generates proc layout structures using the following
** three types.
**
** - When generating only stack traversal information, the compiler will
** generate proc layout structures of type MR_ProcLayout_Traversal.
**
** - When generating stack traversal and procedure id information, plus
** possibly others, the compiler will generate proc layout structures of
** types MR_ProcLayoutUser and MR_ProcLayoutUCI.
*/
struct MR_ProcLayout_Struct {
MR_StackTraversal MR_sle_traversal;
MR_ProcId MR_sle_proc_id;
MR_STATIC_CODE_CONST MR_ExecTrace *MR_sle_exec_trace;
MR_ProcStatic *MR_sle_proc_static;
const MR_uint_least8_t *MR_sle_body_bytes;
const MR_ModuleCommonLayout *MR_sle_module_common_layout;
};
typedef struct MR_ProcLayoutUser_Struct {
MR_StackTraversal MR_user_traversal;
MR_UserProcId MR_user_id;
MR_STATIC_CODE_CONST MR_ExecTrace *MR_sle_exec_trace;
MR_ProcStatic *MR_sle_proc_static;
const MR_uint_least8_t *MR_sle_body_bytes;
const MR_ModuleCommonLayout *MR_sle_module_common_layout;
} MR_ProcLayoutUser;
typedef struct MR_ProcLayoutUCI_Struct {
MR_StackTraversal MR_uci_traversal;
MR_UCIProcId MR_uci_id;
MR_STATIC_CODE_CONST MR_ExecTrace *MR_sle_exec_trace;
MR_ProcStatic *MR_sle_proc_static;
const MR_uint_least8_t *MR_sle_body_bytes;
const MR_ModuleCommonLayout *MR_sle_module_common_layout;
} MR_ProcLayoutUCI;
typedef struct MR_ProcLayout_Traversal_Struct {
MR_StackTraversal MR_trav_traversal;
MR_Word MR_trav_no_proc_id; /* will be -1 */
} MR_ProcLayout_Traversal;
#define MR_PROC_LAYOUT_HAS_PROC_ID(entry) \
(MR_PROC_ID_EXISTS(entry->MR_sle_proc_id))
#define MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry) \
(MR_PROC_LAYOUT_HAS_PROC_ID(entry) && \
entry->MR_sle_exec_trace != NULL)
#define MR_PROC_LAYOUT_HAS_PROC_STATIC(entry) \
(MR_PROC_LAYOUT_HAS_PROC_ID(entry) && \
entry->MR_sle_proc_static != NULL)
#define MR_PROC_LAYOUT_HAS_THIRD_GROUP(entry) \
(MR_PROC_LAYOUT_HAS_PROC_ID(entry) && \
( entry->MR_sle_exec_trace != NULL \
|| entry->MR_sle_proc_static != NULL))
#define MR_sle_code_addr MR_sle_traversal.MR_trav_code_addr
#define MR_sle_succip_locn MR_sle_traversal.MR_trav_succip_locn
#define MR_sle_stack_slots MR_sle_traversal.MR_trav_stack_slots
#define MR_sle_detism MR_sle_traversal.MR_trav_detism
#define MR_sle_user MR_sle_proc_id.MR_proc_user
#define MR_sle_uci MR_sle_proc_id.MR_proc_uci
#define MR_sle_call_label MR_sle_exec_trace->MR_exec_call_label
#define MR_sle_module_layout MR_sle_exec_trace->MR_exec_module_layout
#define MR_sle_labels MR_sle_exec_trace->MR_exec_labels
#define MR_sle_num_labels MR_sle_exec_trace->MR_exec_num_labels
#define MR_sle_tabling_pointer MR_sle_exec_trace->MR_exec_tabling_pointer
#define MR_sle_table_info MR_sle_exec_trace->MR_exec_table_info
#define MR_sle_head_var_nums MR_sle_exec_trace->MR_exec_head_var_nums
#define MR_sle_num_head_vars MR_sle_exec_trace->MR_exec_num_head_vars
#define MR_sle_used_var_names MR_sle_exec_trace->MR_exec_used_var_names
#define MR_sle_max_named_var_num MR_sle_exec_trace->MR_exec_max_named_var_num
#define MR_sle_max_r_num MR_sle_exec_trace->MR_exec_max_r_num
#define MR_sle_maybe_from_full MR_sle_exec_trace->MR_exec_maybe_from_full
#define MR_sle_maybe_io_seq MR_sle_exec_trace->MR_exec_maybe_io_seq
#define MR_sle_maybe_trail MR_sle_exec_trace->MR_exec_maybe_trail
#define MR_sle_maybe_maxfr MR_sle_exec_trace->MR_exec_maybe_maxfr
#define MR_sle_maybe_call_table MR_sle_exec_trace->MR_exec_maybe_call_table
#define MR_sle_maybe_decl_debug MR_sle_exec_trace->MR_exec_maybe_decl_debug
#define MR_sle_maybe_tailrec MR_sle_exec_trace->MR_exec_maybe_tail_rec
#define MR_sle_eval_method(proc_layout_ptr) \
((MR_EvalMethod) (proc_layout_ptr)-> \
MR_sle_exec_trace->MR_exec_eval_method_CAST_ME)
#define MR_sle_trace_level(proc_layout_ptr) \
((MR_TraceLevel) (proc_layout_ptr)-> \
MR_sle_exec_trace->MR_exec_trace_level_CAST_ME)
#define MR_proc_has_io_state_pair(proc_layout_ptr) \
((proc_layout_ptr)->MR_sle_exec_trace->MR_exec_flags \
& MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR)
/* 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_ProcLayout *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_ProcLayout *) & \
MR_PASTE2(mercury_data__proc_layout__, entry)) \
->MR_sle_code_addr = MR_ENTRY(entry); \
} while (0)
#endif
#define MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(sc, detism, slots, succip_locn, \
pf, module, name, arity, mode, proc_static) \
MR_declare_entry(MR_proc_entry_user_name(module, name, \
arity, mode)); \
sc const MR_ProcLayoutUser \
MR_proc_layout_user_name(module, name, arity, mode) = { \
{ \
MR_MAKE_PROC_LAYOUT_ADDR( \
MR_proc_entry_user_name(module, name, \
arity, mode)), \
{ succip_locn }, \
slots, \
detism \
}, \
{ \
pf, \
MR_STRINGIFY(module), \
MR_STRINGIFY(module), \
MR_STRINGIFY(name), \
arity, \
mode \
}, \
NULL, \
(MR_ProcStatic *) proc_static \
}
#define MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(sc, detism, slots, succip_locn, \
module, name, type, arity, mode, proc_static) \
MR_declare_entry(MR_proc_entry_uci_name(module, name, \
type, arity, mode)); \
sc const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(module, name, type, arity, mode) = { \
{ \
MR_MAKE_PROC_LAYOUT_ADDR( \
MR_proc_entry_uci_name(module, name, \
type, arity, mode)), \
{ succip_locn }, \
slots, \
detism \
}, \
{ \
MR_STRINGIFY(type), \
MR_STRINGIFY(module), \
MR_STRINGIFY(module), \
MR_STRINGIFY(name), \
arity, \
mode \
}, \
NULL, \
(MR_ProcStatic *) proc_static \
}
#define MR_NO_EXTERN_DECL
#define MR_STATIC_USER_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(static, detism, slots, \
succip_locn, pf, module, name, arity, mode, \
&MR_proc_static_user_name(module, name, arity, mode))
#define MR_EXTERN_USER_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots, \
succip_locn, pf, module, name, arity, mode, \
&MR_proc_static_user_name(module, name, arity, mode))
#define MR_STATIC_UCI_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
module, name, type, arity, mode) \
MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(static, detism, slots, \
succip_locn, module, name, type, arity, mode, \
&MR_proc_static_uci_name(module, name, type, arity, mode))
#define MR_EXTERN_UCI_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn, \
module, name, type, arity, mode) \
MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots, \
succip_locn, module, name, type, arity, mode, \
&MR_proc_static_uci_name(module, name, type, arity, mode))
#define MR_STATIC_USER_PROC_ID_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(static, detism, slots, \
succip_locn, pf, module, name, arity, mode, NULL)
#define MR_EXTERN_USER_PROC_ID_PROC_LAYOUT(detism, slots, succip_locn, \
pf, module, name, arity, mode) \
MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots, \
succip_locn, pf, module, name, arity, mode, NULL)
#define MR_DECLARE_UCI_PROC_STATIC_LAYOUTS(mod, n, a) \
const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(mod, __Unify__, n, a, 0); \
const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(mod, __Compare__, n, a, 0); \
const MR_ProcLayoutUCI \
MR_proc_layout_uci_name(mod, __CompareRep__, n, a, 0);
/*
** In procedures compiled with execution tracing, three items are stored
** in stack slots with fixed numbers. They are:
**
** the event number of the last event before the call event,
** the call number, and
** the call depth.
**
** Note that the first slot does not store the number of the call event
** itself, but rather the number of the call event minus one. The reason
** for this is that (a) incrementing the number stored in this slot would
** increase executable size, and (b) if the procedure is shallow traced,
** MR_trace may not be called for the call event, so we cannot shift the
** burden of initializing fields to the MR_trace of the call event either.
**
** The following macros will access the fixed slots. They can be used whenever
** MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry) is true; which set you should use
** depends on the determinism of the procedure.
**
** These macros have to be kept in sync with compiler/trace.m.
*/
#define MR_event_num_framevar(base_curfr) MR_based_framevar(base_curfr, 1)
#define MR_call_num_framevar(base_curfr) MR_based_framevar(base_curfr, 2)
#define MR_call_depth_framevar(base_curfr) MR_based_framevar(base_curfr, 3)
#define MR_event_num_stackvar(base_sp) MR_based_stackvar(base_sp, 1)
#define MR_call_num_stackvar(base_sp) MR_based_stackvar(base_sp, 2)
#define MR_call_depth_stackvar(base_sp) MR_based_stackvar(base_sp, 3)
/*
** In model_non procedures compiled with --trace-redo, one or two other items
** are stored in fixed stack slots. These are
**
** the address of the layout structure for the redo event
** the saved copy of the from-full flag (only if trace level is shallow)
**
** The following macros will access these slots. They should be used only from
** within the code that calls MR_trace for the REDO event.
**
** This macros have to be kept in sync with compiler/trace.m.
*/
#define MR_redo_layout_framevar(base_curfr) MR_based_framevar(base_curfr, 4)
#define MR_redo_fromfull_framevar(base_curfr) MR_based_framevar(base_curfr, 5)
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ModuleLayout
**
** The layout structure for a module contains the following fields.
**
** The MR_ml_name field contains the name of the module.
**
** The MR_ml_string_table field contains the module's string table, which
** contains strings referred to by other layout structures in the module
** (initially only the tables containing variables names, referred to from
** label layout structures). The MR_ml_string_table_size field gives the size
** of the table in bytes.
**
** The MR_ml_procs field points to an array containing pointers to the proc
** layout structures of all the procedures in the module; the MR_ml_proc_count
** field gives the number of entries in the array.
**
** The MR_ml_module_file_layout field points to an array of N file layout
** pointers if the module has labels corresponding to contexts that refer
** to the names of N files. For each file, the table gives its name, the
** number of labels in that file in this module, and for each such label,
** it gives its line number and a pointer to its label layout struct.
** The corresponding elements of the label_lineno and label_layout arrays
** refer to the same label. (The reason why they are not stored together
** is space efficiency; adding a 16 bit field to a label layout structure would
** require padding.) The labels are sorted on line number.
**
** The MR_ml_trace_level field gives the trace level that the module was
** compiled with. If the MR_TraceLevel enum is modified, then the
** corresponding function in compiler/trace_params.m must also be updated.
**
** The MR_ml_suppressed_events events field encodes the set of event types
** (ports) that were suppressed when generating code for this module. The bit
** given by the expression (1 << MR_PORT_<PORTTYPE>) will be set in this
** integer iff trace port MR_PORT_<PORTTYPE> is suppressed.
**
** The MR_ml_label_exec_count field points to an array of integers, with each
** integer holding the number of times execution has reached a given label.
** Each label's layout structure records the index of that label in this array.
** The most direct way to go the other way, to find out which label owns a
** particular slot in this array, is to search the label arrays in the file
** layout structures, and test their MR_sll_label_num_in_module fields.
** (If we needed faster access, we could add another array with elements
** corresponding to MR_ml_label_exec_count's pointing to the labels' layout
** structures.)
**
** The MR_ml_num_label_exec_counts field contains the number of elements
** in the MR_ml_label_exec_count array.
*/
typedef struct MR_ModuleFileLayout_Struct {
MR_ConstString MR_mfl_filename;
MR_Integer MR_mfl_label_count;
/* the following fields point to arrays of size MR_mfl_label_count */
const MR_int_least16_t *MR_mfl_label_lineno;
const MR_LabelLayout **MR_mfl_label_layout;
} MR_ModuleFileLayout;
/*
** The version of the data structures in this file -- useful for bootstrapping.
** If you write runtime code that checks this version number and can at least
** handle the previous version of the data structure, it makes it easier to
** bootstrap changes to these data structures.
**
** This number should be kept in sync with layout_version_number in
** compiler/layout_out.m.
*/
#define MR_LAYOUT_VERSION MR_LAYOUT_VERSION__COMMON
#define MR_LAYOUT_VERSION__USER_DEFINED 1
#define MR_LAYOUT_VERSION__EVENTSETNAME 2
#define MR_LAYOUT_VERSION__SYNTH_ATTR 3
#define MR_LAYOUT_VERSION__COMMON 4
struct MR_ModuleCommonLayout_Struct {
MR_uint_least8_t MR_mlc_version_number;
MR_ConstString MR_mlc_name;
MR_Integer MR_mlc_string_table_size;
const char *MR_mlc_string_table;
};
struct MR_ModuleLayout_Struct {
const MR_ModuleCommonLayout *MR_ml_common;
MR_Integer MR_ml_proc_count;
const MR_ProcLayout **MR_ml_procs;
MR_Integer MR_ml_filename_count;
const MR_ModuleFileLayout **MR_ml_module_file_layout;
MR_TraceLevel MR_ml_trace_level;
MR_int_least32_t MR_ml_suppressed_events;
MR_int_least32_t MR_ml_num_label_exec_counts;
MR_Unsigned *MR_ml_label_exec_count;
const char *MR_ml_user_event_set_name;
const char *MR_ml_user_event_set_desc;
MR_int_least16_t MR_ml_user_event_max_num_attr;
MR_int_least16_t MR_ml_num_user_event_specs;
MR_UserEventSpec *MR_ml_user_event_specs;
};
#define MR_ml_version_number MR_ml_common->MR_mlc_version_number
#define MR_ml_name MR_ml_common->MR_mlc_name
#define MR_ml_string_table_size MR_ml_common->MR_mlc_string_table_size
#define MR_ml_string_table MR_ml_common->MR_mlc_string_table
/*-------------------------------------------------------------------------*/
/*
** Definitions for MR_ClosureId
**
** Each closure contains an MR_ClosureId structure. The proc_id field
** identifies the procedure called by the closure. The other fields identify
** the context where the closure was created.
**
** The compiler generates closure id structures as either MR_UserClosureId
** or MR_UCIClosureId structures in order to avoid initializing the
** MR_ProcId union through an inappropriate member.
*/
struct MR_ClosureId_Struct {
MR_ProcId MR_closure_proc_id;
MR_ConstString MR_closure_module_name;
MR_ConstString MR_closure_file_name;
MR_Integer MR_closure_line_number;
MR_ConstString MR_closure_goal_path;
};
struct MR_UserClosureId_Struct {
MR_UserProcId MR_user_closure_proc_id;
MR_ConstString MR_user_closure_module_name;
MR_ConstString MR_user_closure_file_name;
MR_Integer MR_user_closure_line_number;
MR_ConstString MR_user_closure_goal_path;
};
struct MR_UCIClosureId_Struct {
MR_UCIProcId MR_uci_closure_proc_id;
MR_ConstString MR_uci_closure_module_name;
MR_ConstString MR_uci_closure_file_name;
MR_Integer MR_uci_closure_line_number;
MR_ConstString MR_uci_closure_goal_path;
};
#endif /* not MERCURY_STACK_LAYOUT_H */