mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 04:43:53 +00:00
Estimated hours taken: 14 Add a module layout structure containing a string table and a table of pointers to the proc layouts of the module's procedures. This speeds up debugger initialization, and reduces the executable size of the compiler by almost 1.2 Mb (about 3.7%) when compiled with debugging. Instead of representing variables names as strings (32 or 64 bit pointers) in the debugger's static data structures, with the string's prefix representing the variable's number (e.g. "5:X"), represent them as a 16-bit variable number and a 16 bit offset into the module-wide string table. This gains simplicity of processing (no more search for the ":") and reduces the amount of storage required, a bit on 32-bit platforms (we don't have to store "5:ModuleInfo" and "10:ModuleInfo" strings separately, and there are no string prefixes to store) and more on 64-bit platforms. The 16-bit limits are generous. A procedure with more than 64K variables will take forever to compile (that is why we impose a 4K limit on the number of variables in inlining), and even the string tables of typecheck.m and make_hlds require less than four kilobytes each. Exceeding the limits would require code no human would write. Automatically generated code may be a problem, but the help the debugger can give on such code is limited already. In any case, we detect overflows and handle them sensibly. This change does not enhance the debugger to take advantage of the easier availability of variable numbers, except to improve the implementation of retry; that will come later. The inclusion of the procedure table in the module layout structure reduces the cost of registering all procedures in all modules, a task usually performed at the time of the setting of the first breakpoint. This used to require processing all the internal labels in the label table, and thus used to take a few seconds for large executables. The sweep of all internal labels is no longer required, so registering is now much faster. runtime/mercury_stack_layout.h: Add the definition of MR_Module_Layout. Modify label layouts to represent names as offsets in the string table, not as raw character pointers. This required modifing proc layouts to include a pointer to the module's layout, so you can find the string table. Update the macros that look up variable names. runtime/mercury_layout_util.h: Use the updated macros for looking up variable names. runtime/mercury_wrapper.[ch]: Add a new indirect pointer, MR_register_module_layout, which points to a function that registers a module layout, or is NULL if debugging is not enabled. runtime/mercury_init.h: Declare the function whose address may be assigned to MR_register_module_layout in a <main>_init.c file. util/mkinit.c: Initialize MR_register_module_layout with either the address of MR_register_module_layout_real or NULL, depending on whether debugging is enabled or not. compiler/continuation_info.m: Don't give names (V_n) to nameless variables, because we don't want them to be included in the variables debugging knows about. compiler/llds.m: Add a new function symbol to the type data_addr, which stands for the module layout structure of the named (now always the current) module. Add a new function symbol to the type rval_const. The new function symbols, multi_string_const, contains an array of characters of an explicitly given length, which consists of several strings, each terminated by a null character. compiler/llds_out.m: Accommodate the changes to llds.m, and expand the module initialization code to register the module layout structure, if the pointer to the registration function is not NULL. compiler/stack_layout.m: Generate the new data structures for representing variable names, as well as the module layout. compiler/mercury_compile.m: Rename some variables to reflect the fact that stack_layout.m can now include a module layout structure in the list of static layout structures it returns. compiler/dupelim.m: compiler/exprn_aux.m: compiler/jumpopt.m: compiler/opt_debug.m: Minor changes to accommodate multi_string_consts. trace/mercury_trace_tables.[ch]: Replace the old data structures for recording information about each debuggable module with the module layout structure, and register module layout structures directly, instead of trying to discover them through the internal label table. trace/mercury_trace.[ch]: Now that it is more easily accessible, use variable numbers instead of variable names to find the current locations of the input arguments when implementing retry. Unlike our previous method, this works even if the user names some variables HeadVar__1, etc. Remove an unnecessary export of an internal function. trace/mercury_trace_external.c: trace/mercury_trace_internal.c: runtime/mercury_layout_util.c: Use the updated macros for looking up variable names.
565 lines
19 KiB
C
565 lines
19 KiB
C
/*
|
|
** Copyright (C) 1998-1999 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 the stack layout data structures.
|
|
**
|
|
** 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 compiler/stack_layout.m as well.
|
|
*/
|
|
|
|
#include "mercury_types.h"
|
|
#include "mercury_std.h" /* for MR_VARIABLE_SIZED */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_PredFunc. This enum should EXACTLY match the definition
|
|
** of the `pred_or_func' type in browser/debugger_interface.
|
|
*/
|
|
|
|
typedef enum { MR_PREDICATE, MR_FUNCTION } MR_PredFunc;
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** 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.
|
|
*/
|
|
|
|
typedef 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_AT_MOST_ZERO(d) (((d) & 3) == 0)
|
|
#define MR_DETISM_AT_MOST_ONE(d) (((d) & 3) == 2)
|
|
#define MR_DETISM_AT_MOST_MANY(d) (((d) & 1) != 0)
|
|
|
|
#define MR_DETISM_CAN_FAIL(d) (((d) & 4) != 0)
|
|
|
|
#define MR_DETISM_FIRST_SOLN(d) (((d) & 8) != 0)
|
|
|
|
#define MR_DETISM_DET_STACK(d) (!MR_DETISM_AT_MOST_MANY(d) \
|
|
|| MR_DETISM_FIRST_SOLN(d))
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Long_Lval and MR_Short_Lval
|
|
*/
|
|
|
|
/*
|
|
** MR_Long_Lval is a uint_least32_t which describes an location. This includes
|
|
** lvals such as stack slots, general registers, and special registers
|
|
** such as succip, hp, etc, as well as locations whose address is given
|
|
** as a typeinfo inside the type class info structure pointed to by an lval.
|
|
**
|
|
** What kind of location an MR_Long_Lval refers to is encoded using
|
|
** a low tag with MR_LONG_LVAL_TAGBITS bits; the type MR_Lval_Type describes
|
|
** the different tag values. The interpretation of the rest of the word
|
|
** depends on the location type:
|
|
**
|
|
** Locn Tag Rest
|
|
** r(Num) 0 Num (register number)
|
|
** f(Num) 1 Num (register number)
|
|
** stackvar(Num) 2 Num (stack slot number)
|
|
** framevar(Num) 3 Num (stack slot number)
|
|
** succip 4
|
|
** maxfr 5
|
|
** curfr 6
|
|
** hp 7
|
|
** sp 8
|
|
** indirect(Base, N) 9 See below
|
|
** unknown 10 (The location is not known)
|
|
**
|
|
** For indirect references, the word exclusive of the tag consists of
|
|
** (a) an integer with MR_LONG_LVAL_OFFSETBITS bits giving the index
|
|
** of the typeinfo inside a type class info (to be interpreted by
|
|
** private_builtin:type_info_from_typeclass_info), and (b) a MR_Long_Lval
|
|
** value giving the location of the pointer to the type class info.
|
|
** This MR_Long_Lval value will *not* have an indirect tag.
|
|
**
|
|
** This data is generated in stack_layout__represent_locn_as_int,
|
|
** which must be kept in sync with the constants and macros defined here.
|
|
*/
|
|
|
|
typedef uint_least32_t MR_Long_Lval;
|
|
|
|
typedef enum {
|
|
MR_LONG_LVAL_TYPE_R,
|
|
MR_LONG_LVAL_TYPE_F,
|
|
MR_LONG_LVAL_TYPE_STACKVAR,
|
|
MR_LONG_LVAL_TYPE_FRAMEVAR,
|
|
MR_LONG_LVAL_TYPE_SUCCIP,
|
|
MR_LONG_LVAL_TYPE_MAXFR,
|
|
MR_LONG_LVAL_TYPE_CURFR,
|
|
MR_LONG_LVAL_TYPE_HP,
|
|
MR_LONG_LVAL_TYPE_SP,
|
|
MR_LONG_LVAL_TYPE_INDIRECT,
|
|
MR_LONG_LVAL_TYPE_UNKNOWN
|
|
} MR_Long_Lval_Type;
|
|
|
|
/* This must be in sync with stack_layout__long_lval_tag_bits */
|
|
#define MR_LONG_LVAL_TAGBITS 4
|
|
|
|
#define MR_LONG_LVAL_TYPE(Locn) \
|
|
((MR_Long_Lval_Type) \
|
|
(((Word) Locn) & ((1 << MR_LONG_LVAL_TAGBITS) - 1)))
|
|
|
|
#define MR_LONG_LVAL_NUMBER(Locn) \
|
|
((int) ((Word) Locn) >> MR_LONG_LVAL_TAGBITS)
|
|
|
|
/* This must be in sync with stack_layout__offset_bits */
|
|
#define MR_LONG_LVAL_OFFSETBITS 6
|
|
|
|
#define MR_LONG_LVAL_INDIRECT_OFFSET(LocnNumber) \
|
|
((int) ((LocnNumber) & ((1 << MR_LONG_LVAL_OFFSETBITS) - 1)))
|
|
|
|
#define MR_LONG_LVAL_INDIRECT_BASE_LVAL(LocnNumber) \
|
|
(((Word) (LocnNumber)) >> MR_LONG_LVAL_OFFSETBITS)
|
|
|
|
#define MR_LONG_LVAL_STACKVAR(n) \
|
|
((Word) ((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_STACKVAR)
|
|
|
|
#define MR_LONG_LVAL_FRAMEVAR(n) \
|
|
((Word) ((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_FRAMEVAR)
|
|
|
|
#define MR_LONG_LVAL_R_REG(n) \
|
|
((Word) ((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_R)
|
|
|
|
/*
|
|
** MR_Short_Lval is a uint_least8_t which describes an location. This includes
|
|
** lvals such as stack slots and general registers that have small numbers,
|
|
** and special registers such as succip, hp, etc.
|
|
**
|
|
** What kind of location an MR_Long_Lval refers to is encoded using
|
|
** a low tag with 2 bits; the type MR_Short_Lval_Type describes
|
|
** the different tag values. The interpretation of the rest of the word
|
|
** depends on the location type:
|
|
**
|
|
** Locn Tag Rest
|
|
** r(Num) 0 Num (register number)
|
|
** stackvar(Num) 1 Num (stack slot number)
|
|
** framevar(Num) 2 Num (stack slot number)
|
|
** special reg 3 MR_Long_Lval_Type
|
|
**
|
|
** This data is generated in stack_layout__represent_locn_as_byte,
|
|
** which must be kept in sync with the constants and macros defined here.
|
|
*/
|
|
|
|
typedef uint_least8_t MR_Short_Lval;
|
|
|
|
typedef enum {
|
|
MR_SHORT_LVAL_TYPE_R,
|
|
MR_SHORT_LVAL_TYPE_STACKVAR,
|
|
MR_SHORT_LVAL_TYPE_FRAMEVAR,
|
|
MR_SHORT_LVAL_TYPE_SPECIAL
|
|
} MR_Short_Lval_Type;
|
|
|
|
/* This must be in sync with stack_layout__short_lval_tag_bits */
|
|
#define MR_SHORT_LVAL_TAGBITS 2
|
|
|
|
#define MR_SHORT_LVAL_TYPE(Locn) \
|
|
((MR_Short_Lval_Type) \
|
|
(((Word) Locn) & ((1 << MR_SHORT_LVAL_TAGBITS) - 1)))
|
|
|
|
#define MR_SHORT_LVAL_STACKVAR(n) \
|
|
((MR_Short_Lval) (((n) << MR_SHORT_LVAL_TAGBITS) \
|
|
+ MR_SHORT_LVAL_TYPE_STACKVAR))
|
|
|
|
#define MR_SHORT_LVAL_FRAMEVAR(n) \
|
|
((MR_Short_Lval) (((n) << MR_SHORT_LVAL_TAGBITS) \
|
|
+ MR_SHORT_LVAL_TYPE_FRAMEVAR))
|
|
|
|
#define MR_SHORT_LVAL_R_REG(n) \
|
|
((MR_Short_Lval) (((n) << MR_SHORT_LVAL_TAGBITS) \
|
|
+ MR_SHORT_LVAL_TYPE_R))
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Stack_Layout_Vars
|
|
*/
|
|
|
|
/*
|
|
** If MR_slvs_tvars == NULL, there are no type parameters.
|
|
** If it is != NULL, then MR_slvs_tvars->MR_tp_param_count is the number
|
|
** of type parameters, and the element at index i in the array
|
|
** MR_slvs_tvars->MR_tp_param_locns 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). If one of these type variables
|
|
** is not referred to by the variables described in MR_slvs_pairs,
|
|
** the corresponding entry will be zero.
|
|
*/
|
|
|
|
typedef struct MR_Type_Param_Locns_Struct {
|
|
uint_least32_t MR_tp_param_count;
|
|
MR_Long_Lval MR_tp_param_locns[MR_VARIABLE_SIZED];
|
|
} MR_Type_Param_Locns;
|
|
|
|
/*
|
|
** This structure describes the name of a live value, if it has any.
|
|
**
|
|
** The MR_var_num field is zero if the live value is not a variable;
|
|
** if it is, it gives the HLDS number of the variable.
|
|
**
|
|
** The MR_var_name_offset field gives the offset, within the string
|
|
** table of the module containing the layout structure, of the name
|
|
** of the variable. If the variable has no name, or if the live value
|
|
** is not a variable, the offset will be zero.
|
|
*/
|
|
|
|
typedef struct MR_Var_Name_Struct {
|
|
uint_least16_t MR_var_num;
|
|
uint_least16_t MR_var_name_offset;
|
|
} MR_Var_Name;
|
|
|
|
/*
|
|
** The MR_slvs_var_count field should be set to a negative number
|
|
** if there is no information about the variables live at the label.
|
|
*/
|
|
|
|
typedef struct MR_Stack_Layout_Vars_Struct {
|
|
void *MR_slvs_var_count;
|
|
/* the remaining fields are present only if MR_sll_var_count > 0 */
|
|
void *MR_slvs_locns_types;
|
|
MR_Var_Name *MR_slvs_names;
|
|
MR_Type_Param_Locns *MR_slvs_tvars;
|
|
} MR_Stack_Layout_Vars;
|
|
|
|
#define MR_SHORT_COUNT_BITS 10
|
|
#define MR_SHORT_COUNT_MASK ((1 << MR_SHORT_COUNT_BITS) - 1)
|
|
|
|
#define MR_has_valid_var_count(slvs) \
|
|
(((Integer) ((slvs)->MR_slvs_var_count)) >= 0)
|
|
#define MR_has_valid_var_info(slvs) \
|
|
(((Integer) ((slvs)->MR_slvs_var_count)) > 0)
|
|
#define MR_long_desc_var_count(slvs) \
|
|
(((Integer) ((slvs)->MR_slvs_var_count)) >> MR_SHORT_COUNT_BITS)
|
|
#define MR_short_desc_var_count(slvs) \
|
|
(((Integer) ((slvs)->MR_slvs_var_count)) & MR_SHORT_COUNT_MASK)
|
|
#define MR_all_desc_var_count(slvs) \
|
|
(MR_long_desc_var_count(slvs) + MR_short_desc_var_count(slvs))
|
|
#define MR_var_pti(slvs, i) \
|
|
(((MR_PseudoTypeInfo **) ((slvs)->MR_slvs_locns_types))[(i)])
|
|
#define MR_end_of_var_ptis(slvs) \
|
|
(&MR_var_pti((slvs), MR_all_desc_var_count(slvs)))
|
|
#define MR_long_desc_var_locn(slvs, i) \
|
|
(((uint_least32_t *) MR_end_of_var_ptis(slvs))[(i)])
|
|
#define MR_end_of_long_desc_var_locns(slvs) \
|
|
(&MR_long_desc_var_locn((slvs), MR_long_desc_var_count(slvs)))
|
|
#define MR_short_desc_var_locn(slvs, i) \
|
|
(((uint_least8_t *) MR_end_of_long_desc_var_locns(slvs))[(i)])
|
|
|
|
#define MR_name_if_present(module_layout, vars, i) \
|
|
(((vars)->MR_slvs_names == NULL) ? "" : \
|
|
((module_layout)->MR_ml_string_table + \
|
|
(vars)->MR_slvs_names[(i)].MR_var_name_offset))
|
|
|
|
#define MR_name_if_present_from_label(label_layout, i) \
|
|
MR_name_if_present( \
|
|
(label_layout)->MR_sll_entry->MR_sle_module_layout, \
|
|
&((label_layout)->MR_sll_var_info), \
|
|
(i))
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Stack_Layout_Entry
|
|
*/
|
|
|
|
/*
|
|
** This structure records information about a procedure.
|
|
** The structure has three groups of fields:
|
|
**
|
|
** (1) those needed for traversing the stack;
|
|
** (2) those needed for identifying the procedure;
|
|
** (3) those needed for execution tracing.
|
|
**
|
|
** For accurate garbage collection, we only need group (1).
|
|
** For stack tracing, we need groups (1) and (2).
|
|
** For execution tracing, we need groups (1), (2) and (3).
|
|
**
|
|
** To save space, for each use we only include the fields that belong
|
|
** to the needed groups, plus the first field in the first non-included group,
|
|
** which is set to a special value to indicate the absence of the group
|
|
** and any following groups.
|
|
**
|
|
** Group (1) is always present and meaningful.
|
|
** Group (2) is present and meaningful
|
|
** if MR_ENTRY_LAYOUT_HAS_PROC_ID(entry) evaluates to true.
|
|
** Group (3) is present and meaningful
|
|
** if MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(entry) evaluates to true.
|
|
**
|
|
** Group (2) fields have a different interpretation if the procedure is
|
|
** compiler-generated. You can test whether this is the case by using the macro
|
|
** MR_ENTRY_LAYOUT_COMPILER_GENERATED, but only after checking that
|
|
** MR_ENTRY_LAYOUT_HAS_PROC_ID is true.
|
|
**
|
|
** For further details on the semantics of the fields, see stack_layout.m.
|
|
*/
|
|
|
|
/*
|
|
** The places that know about the structure of procedure ids include
|
|
** browser/dl.m and of course compiler/stack_layout, besides all the places
|
|
** that refer to the C types we now define.
|
|
*/
|
|
|
|
typedef struct MR_Stack_Layout_User_Proc_Struct {
|
|
MR_PredFunc MR_user_pred_or_func;
|
|
ConstString MR_user_decl_module;
|
|
ConstString MR_user_def_module;
|
|
ConstString MR_user_name;
|
|
Integer MR_user_arity;
|
|
Integer MR_user_mode;
|
|
} MR_Stack_Layout_User_Proc;
|
|
|
|
typedef struct MR_Stack_Layout_Compiler_Proc_Struct {
|
|
ConstString MR_comp_type_name;
|
|
ConstString MR_comp_type_module;
|
|
ConstString MR_comp_def_module;
|
|
ConstString MR_comp_pred_name;
|
|
Integer MR_comp_arity;
|
|
Integer MR_comp_mode;
|
|
} MR_Stack_Layout_Compiler_Proc;
|
|
|
|
typedef union MR_Stack_Layout_Proc_Id_Union {
|
|
MR_Stack_Layout_User_Proc MR_proc_user;
|
|
MR_Stack_Layout_Compiler_Proc MR_proc_comp;
|
|
} MR_Stack_Layout_Proc_Id;
|
|
|
|
typedef struct MR_Stack_Layout_Entry_Struct {
|
|
/* stack traversal group */
|
|
Code *MR_sle_code_addr;
|
|
MR_Long_Lval MR_sle_succip_locn;
|
|
int_least16_t MR_sle_stack_slots;
|
|
MR_Determinism MR_sle_detism;
|
|
|
|
/* proc id group */
|
|
MR_Stack_Layout_Proc_Id MR_sle_proc_id;
|
|
|
|
/* exec trace group */
|
|
struct MR_Stack_Layout_Label_Struct
|
|
*MR_sle_call_label;
|
|
struct MR_Module_Layout_Struct
|
|
*MR_sle_module_layout;
|
|
int_least16_t MR_sle_maybe_from_full;
|
|
int_least16_t MR_sle_maybe_decl_debug;
|
|
} MR_Stack_Layout_Entry;
|
|
|
|
#define MR_sle_user MR_sle_proc_id.MR_proc_user
|
|
#define MR_sle_comp MR_sle_proc_id.MR_proc_comp
|
|
|
|
#define MR_ENTRY_LAYOUT_HAS_PROC_ID(entry) \
|
|
((Word) entry->MR_sle_user.MR_user_pred_or_func != -1)
|
|
|
|
#define MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(entry) \
|
|
(MR_ENTRY_LAYOUT_HAS_PROC_ID(entry) \
|
|
&& entry->MR_sle_call_label != NULL)
|
|
|
|
#define MR_ENTRY_LAYOUT_COMPILER_GENERATED(entry) \
|
|
((Unsigned) entry->MR_sle_user.MR_user_pred_or_func \
|
|
> MR_FUNCTION)
|
|
|
|
/*
|
|
** Define a layout structure for a procedure, containing information
|
|
** for the first two groups of fields.
|
|
**
|
|
** 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_ENTRY_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_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 have their own
|
|
** compiler-generated type.)
|
|
*/
|
|
|
|
#define MR_ENTRY_NO_SLOT_COUNT -1
|
|
|
|
#ifdef MR_STATIC_CODE_ADDRESSES
|
|
#define MR_MAKE_PROC_LAYOUT_ADDR(entry) STATIC(entry)
|
|
#define MR_INIT_PROC_LAYOUT_ADDR(entry) do { } while (0)
|
|
#else
|
|
#define MR_MAKE_PROC_LAYOUT_ADDR(entry) ((Code *) NULL)
|
|
#define MR_INIT_PROC_LAYOUT_ADDR(entry) \
|
|
do { \
|
|
((MR_Stack_Layout_Entry *) & \
|
|
mercury_data__layout__##entry) \
|
|
->MR_sle_code_addr = ENTRY(entry); \
|
|
} while (0)
|
|
#endif
|
|
|
|
#define MR_MAKE_PROC_LAYOUT(entry, detism, slots, succip_locn, \
|
|
pf, module, name, arity, mode) \
|
|
MR_Stack_Layout_Entry mercury_data__layout__##entry = { \
|
|
MR_MAKE_PROC_LAYOUT_ADDR(entry), \
|
|
succip_locn, \
|
|
slots, \
|
|
detism, \
|
|
{{ \
|
|
pf, \
|
|
module, \
|
|
module, \
|
|
name, \
|
|
arity, \
|
|
mode \
|
|
}}, \
|
|
NULL \
|
|
}
|
|
|
|
/*
|
|
** 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_ENTRY_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 an execution trace options that
|
|
** require REDO events, one other item is stored in a fixed stack slot.
|
|
** This is
|
|
**
|
|
** the address of the layout structure for the redo event
|
|
**
|
|
** The following macro will access it. This macro 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)
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Stack_Layout_Label
|
|
*/
|
|
|
|
typedef struct MR_Stack_Layout_Label_Struct {
|
|
MR_Stack_Layout_Entry *MR_sll_entry;
|
|
#ifdef MR_LABEL_STRUCTS_INCLUDE_NUMBER
|
|
Integer MR_sll_label_num;
|
|
#endif
|
|
MR_Stack_Layout_Vars MR_sll_var_info;
|
|
} MR_Stack_Layout_Label;
|
|
|
|
#ifdef MR_LABEL_STRUCTS_INCLUDE_NUMBER
|
|
#define UNKNOWN_INTERNAL_LABEL_FIELD Integer f2;
|
|
#define UNKNOWN_INTERNAL_LABEL_NUMBER (Integer) -1,
|
|
#else
|
|
#define UNKNOWN_INTERNAL_LABEL_FIELD
|
|
#define UNKNOWN_INTERNAL_LABEL_NUMBER
|
|
#endif
|
|
|
|
/*
|
|
** Define a stack layout for an internal label.
|
|
**
|
|
** The MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY variant allows you to specify
|
|
** the label name (l) and the entry label name (e) independently, which
|
|
** means that it can be used for labels in code fragments which are
|
|
** simultaneously part of several procedures. (Some hand-written code
|
|
** in the library is like this; the different procedures usually differ
|
|
** only in attributes such as the uniqueness of their arguments.)
|
|
**
|
|
** The MR_MAKE_INTERNAL_LAYOUT variant assumes that the internal label
|
|
** is in the procedure named by the entry label.
|
|
**
|
|
** The only useful information in the structures created by these macros
|
|
** 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_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(l, e) \
|
|
MR_Stack_Layout_Label mercury_data__layout__##l = { \
|
|
&mercury_data__layout__##e, \
|
|
UNKNOWN_INTERNAL_LABEL_NUMBER \
|
|
{ \
|
|
(void *) -1, /* No info about live values */ \
|
|
NULL, \
|
|
NULL, \
|
|
NULL \
|
|
} \
|
|
}
|
|
|
|
#define MR_MAKE_INTERNAL_LAYOUT(e, n) \
|
|
MR_MAKE_INTERNAL_LAYOUT_WITH_ENTRY(e##_i##n, e)
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
** Definitions for MR_Module_Layout
|
|
**
|
|
** The layout struct for a module contains two main components.
|
|
**
|
|
** The first is a 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 second is a table containing pointers to the proc layout structures
|
|
** of all the procedures in the module.
|
|
*/
|
|
|
|
typedef struct MR_Module_Layout_Struct {
|
|
String MR_ml_name;
|
|
Integer MR_ml_string_table_size;
|
|
char *MR_ml_string_table;
|
|
Integer MR_ml_proc_count;
|
|
MR_Stack_Layout_Entry **MR_ml_procs;
|
|
} MR_Module_Layout;
|
|
|
|
#endif /* not MERCURY_STACK_LAYOUT_H */
|