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