mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-13 21:04:00 +00:00
Estimated hours taken: 36 Instead of generating the layout structures of labels, procs and modules as rvals, generate them almost entirely as C structures. This will make future modifications much easier, since mismatches between what the runtime expects and what the compiler generates will now be pointed out by the C compiler. (It also reduces the size of the C source files generated with debugging enabled by about 5%.) Layout structures contain a few components that are not well-typed in C; we continue to generate these as rvals. Closure layout structures used to have a well-typed part and a non-well-typed part. We now generate the well-typed part as a separate structure, pointed to from the other. We also extend the well-typed part, so that instead of just giving the name the called procedure, it also identifies the source location where the closure was constructed. This could be useful for the debugger and for deep profiling. This diff also includes a change to get the compiler to bootstrap with lcc in grade none.gc.debug.tr: initializing the string tables in module layouts not as a string but as an array of characters. runtime/mercury_stack_layout.h: Reorganize the definitions of layout structures. Rename Stack_Layout_Entry structures as Proc_Layout structures, and Stack_Layout_Label structures as Label_Layout structures. (The debugger paper refers to the structures by the new names.) Fold the Stack_Layout_Vars structure into the structure that contains it, the Label_Layout structure. Add a Closure_Id structure that contains a Proc_Id structure as well as extra information identifying the source location where the closure was created. Create "short" versions of the Proc_Layout structures, which contain only the first one or two of the three groups of fields. Previously, the Mercury compiler would define new C types when it generated such short structures. Since we are not defining new C types anymore, there must be a C type for every kind of structure the Mercury compiler can generate. We now also have separate variants for the layouts of user-defined and compiler-generated procedures, since the format of their procedure id information is different. While the runtime system refers to their procedure id information through a union, the C types of the structures generated by the Mercury compiler do not use a union, since a union cannot be initialized through its second member. Make the constant fields of structures const, since we now generate values of those structure types, and initialize them with constant data. Move the documentation of layout structures here from stack_layout.m. runtime/mercury_ho_call.h: Instead of bodily including an MR_Proc_Id structure in closures, include a pointer to the more detailed MR_Closure_Id structure. runtime/mercury_accurate_gc.c: runtime/mercury_agc_debug.c: runtime/mercury_init.h: runtime/mercury_label.[ch]: runtime/mercury_layout_util.[ch]: Minor updates to conform to changes in mercury_stack_layout.h. runtime/mercury_goto.h: Use separate naming schemes for label layout structures and proc layout structures. library/exception.m: Minor updates to conform to changes in mercury_stack_layout.h. compiler/layout.m: A new module that defines data structures for label, proc and module layout structures and for closure id structures. compiler/layout_out.m: A new module that converts the Mercury data structures of layout.m into declarations and definitions of C data structures. compiler/stack_layout.m: Generate the new layout structures instead of rvals. Move the documentation of layout structures from here to runtime/mercury_stack_layout.h, since this module is no longer aware of some of their details. compiler/llds.m: Make layout structures a separate kind of compiler-generated data. compiler/llds_out.m: Remove the code for the output of layout structures; call layout_out.m instead. compiler/llds_out.m: compiler/rtti_out.m: Turn some predicates into functions. compiler/code_gen.m: compiler/code_info.m: compiler/llds.m: compiler/mercury_compile.m: compiler/unify_gen.m: Instead of handling closure layouts like other static data, handle them separately. Add a counter to the code_info structure in order to allow closure id structures to be identified uniquely by a pair consisting of the id of the procedure that generates them and a closure sequence number within that procedure. compiler/llds_common.m: Look for common rvals among the rvals in layout structures. compiler/opt_debug.m: Generate developer-friendly names for layout structure references. browser/dl.m: Update the code for constructing closure layouts.
308 lines
10 KiB
Mathematica
308 lines
10 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2000-2001 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: trace_params.m.
|
|
%
|
|
% Author: zs.
|
|
%
|
|
% This module defines the parameters of execution tracing at various trace
|
|
% levels and with various settings of the --suppress-trace option.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module trace_params.
|
|
|
|
:- interface.
|
|
|
|
:- import_module llds.
|
|
:- import_module bool.
|
|
|
|
:- type trace_level.
|
|
:- type trace_suppress_items.
|
|
|
|
% the bool should be the setting of the `require_tracing' option.
|
|
:- pred convert_trace_level(string::in, bool::in, trace_level::out) is semidet.
|
|
|
|
:- pred convert_trace_suppress(string::in, trace_suppress_items::out)
|
|
is semidet.
|
|
|
|
% These functions check for various properties of the trace level.
|
|
:- func trace_level_is_none(trace_level) = bool.
|
|
:- func trace_level_needs_fixed_slots(trace_level) = bool.
|
|
:- func trace_level_needs_from_full_slot(trace_level) = bool.
|
|
:- func trace_level_needs_decl_debug_slots(trace_level) = bool.
|
|
:- func trace_level_allows_delay_death(trace_level) = bool.
|
|
:- func trace_needs_return_info(trace_level, trace_suppress_items) = bool.
|
|
:- func trace_needs_all_var_names(trace_level, trace_suppress_items) = bool.
|
|
:- func trace_needs_proc_body_reps(trace_level, trace_suppress_items) = bool.
|
|
:- func trace_needs_port(trace_level, trace_suppress_items, trace_port) = bool.
|
|
|
|
:- func trace_level_none = trace_level.
|
|
|
|
% This is used to represent the trace level in the module layout.
|
|
:- func trace_level_rep(trace_level) = string.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module char, string, list, set.
|
|
|
|
:- type trace_level
|
|
---> none
|
|
; shallow
|
|
; deep
|
|
; decl
|
|
; decl_rep.
|
|
|
|
:- type trace_suppress_item
|
|
---> port(trace_port)
|
|
; return_info
|
|
; all_var_names
|
|
; proc_body_reps.
|
|
|
|
:- type trace_suppress_items == set(trace_suppress_item).
|
|
|
|
trace_level_none = none.
|
|
|
|
convert_trace_level("minimum", no, none).
|
|
convert_trace_level("minimum", yes, shallow).
|
|
convert_trace_level("shallow", _, shallow).
|
|
convert_trace_level("deep", _, deep).
|
|
convert_trace_level("decl", _, decl).
|
|
convert_trace_level("rep", _, decl_rep).
|
|
convert_trace_level("default", no, none).
|
|
convert_trace_level("default", yes, deep).
|
|
|
|
trace_level_is_none(none) = yes.
|
|
trace_level_is_none(shallow) = no.
|
|
trace_level_is_none(deep) = no.
|
|
trace_level_is_none(decl) = no.
|
|
trace_level_is_none(decl_rep) = no.
|
|
|
|
trace_level_needs_fixed_slots(none) = no.
|
|
trace_level_needs_fixed_slots(shallow) = yes.
|
|
trace_level_needs_fixed_slots(deep) = yes.
|
|
trace_level_needs_fixed_slots(decl) = yes.
|
|
trace_level_needs_fixed_slots(decl_rep) = yes.
|
|
|
|
trace_level_needs_from_full_slot(none) = no.
|
|
trace_level_needs_from_full_slot(shallow) = yes.
|
|
trace_level_needs_from_full_slot(deep) = no.
|
|
trace_level_needs_from_full_slot(decl) = no.
|
|
trace_level_needs_from_full_slot(decl_rep) = no.
|
|
|
|
trace_level_needs_decl_debug_slots(none) = no.
|
|
trace_level_needs_decl_debug_slots(shallow) = no.
|
|
trace_level_needs_decl_debug_slots(deep) = no.
|
|
trace_level_needs_decl_debug_slots(decl) = yes.
|
|
trace_level_needs_decl_debug_slots(decl_rep) = yes.
|
|
|
|
trace_level_allows_delay_death(none) = no.
|
|
trace_level_allows_delay_death(shallow) = no.
|
|
trace_level_allows_delay_death(deep) = yes.
|
|
trace_level_allows_delay_death(decl) = yes.
|
|
trace_level_allows_delay_death(decl_rep) = yes.
|
|
|
|
trace_needs_return_info(TraceLevel, TraceSuppressItems) = Need :-
|
|
(
|
|
trace_level_has_return_info(TraceLevel) = yes,
|
|
\+ set__member(return_info, TraceSuppressItems)
|
|
->
|
|
Need = yes
|
|
;
|
|
Need = no
|
|
).
|
|
|
|
trace_needs_all_var_names(TraceLevel, TraceSuppressItems) = Need :-
|
|
(
|
|
trace_level_has_all_var_names(TraceLevel) = yes,
|
|
\+ set__member(all_var_names, TraceSuppressItems)
|
|
->
|
|
Need = yes
|
|
;
|
|
Need = no
|
|
).
|
|
|
|
trace_needs_proc_body_reps(TraceLevel, TraceSuppressItems) = Need :-
|
|
(
|
|
trace_level_has_proc_body_reps(TraceLevel) = yes,
|
|
\+ set__member(proc_body_reps, TraceSuppressItems)
|
|
->
|
|
Need = yes
|
|
;
|
|
Need = no
|
|
).
|
|
|
|
:- func trace_level_has_return_info(trace_level) = bool.
|
|
:- func trace_level_has_all_var_names(trace_level) = bool.
|
|
:- func trace_level_has_proc_body_reps(trace_level) = bool.
|
|
|
|
trace_level_has_return_info(none) = no.
|
|
trace_level_has_return_info(shallow) = yes.
|
|
trace_level_has_return_info(deep) = yes.
|
|
trace_level_has_return_info(decl) = yes.
|
|
trace_level_has_return_info(decl_rep) = yes.
|
|
|
|
trace_level_has_all_var_names(none) = no.
|
|
trace_level_has_all_var_names(shallow) = no.
|
|
trace_level_has_all_var_names(deep) = no.
|
|
trace_level_has_all_var_names(decl) = yes.
|
|
trace_level_has_all_var_names(decl_rep) = yes.
|
|
|
|
trace_level_has_proc_body_reps(none) = no.
|
|
trace_level_has_proc_body_reps(shallow) = no.
|
|
trace_level_has_proc_body_reps(deep) = no.
|
|
trace_level_has_proc_body_reps(decl) = no.
|
|
trace_level_has_proc_body_reps(decl_rep) = yes.
|
|
|
|
convert_trace_suppress(SuppressString, SuppressItemSet) :-
|
|
SuppressWords = string__words(char_is_comma, SuppressString),
|
|
list__map(convert_item_name, SuppressWords, SuppressItemLists),
|
|
list__condense(SuppressItemLists, SuppressItems),
|
|
set__list_to_set(SuppressItems, SuppressItemSet).
|
|
|
|
:- pred char_is_comma(char::in) is semidet.
|
|
|
|
char_is_comma(',').
|
|
|
|
:- func convert_port_name(string) = trace_port is semidet.
|
|
|
|
% The call port cannot be disabled, because its layout structure is
|
|
% referred to implicitly by the redo command in mdb.
|
|
%
|
|
% The exception port cannot be disabled, because it is never put into
|
|
% compiler-generated code in the first place; such events are created
|
|
% on the fly by library/exception.m.
|
|
% convert_port_name("call") = call.
|
|
convert_port_name("exit") = exit.
|
|
convert_port_name("fail") = fail.
|
|
convert_port_name("redo") = redo.
|
|
% convert_port_name("excp") = exception.
|
|
convert_port_name("exception") = exception.
|
|
convert_port_name("cond") = ite_cond.
|
|
convert_port_name("ite_cond") = ite_cond.
|
|
convert_port_name("then") = ite_then.
|
|
convert_port_name("ite_then") = ite_then.
|
|
convert_port_name("else") = ite_else.
|
|
convert_port_name("ite_else") = ite_else.
|
|
convert_port_name("nege") = neg_enter.
|
|
convert_port_name("neg_enter") = neg_enter.
|
|
convert_port_name("negs") = neg_success.
|
|
convert_port_name("neg_success") = neg_success.
|
|
convert_port_name("negf") = neg_failure.
|
|
convert_port_name("neg_failure") = neg_failure.
|
|
convert_port_name("swtc") = switch.
|
|
convert_port_name("switch") = switch.
|
|
convert_port_name("disj") = disj.
|
|
convert_port_name("frst") = nondet_pragma_first.
|
|
convert_port_name("nondet_pragma_first") = nondet_pragma_first.
|
|
convert_port_name("latr") = nondet_pragma_first.
|
|
convert_port_name("nondet_pragma_later") = nondet_pragma_later.
|
|
|
|
:- func convert_port_class_name(string) = list(trace_port) is semidet.
|
|
|
|
convert_port_class_name("interface") =
|
|
[call, exit, redo, fail, exception].
|
|
convert_port_class_name("internal") =
|
|
[ite_then, ite_else, switch, disj].
|
|
convert_port_class_name("context") =
|
|
[ite_cond, neg_enter, neg_success, neg_failure].
|
|
|
|
:- func convert_other_name(string) = trace_suppress_item is semidet.
|
|
|
|
convert_other_name("return") = return_info.
|
|
convert_other_name("return_info") = return_info.
|
|
convert_other_name("names") = all_var_names.
|
|
convert_other_name("all_var_names") = all_var_names.
|
|
convert_other_name("bodies") = proc_body_reps.
|
|
convert_other_name("proc_body_reps") = proc_body_reps.
|
|
|
|
:- pred convert_item_name(string::in, list(trace_suppress_item)::out)
|
|
is semidet.
|
|
|
|
convert_item_name(String, Names) :-
|
|
( convert_port_name(String) = PortName ->
|
|
Names = [port(PortName)]
|
|
; convert_port_class_name(String) = PortNames ->
|
|
list__map(wrap_port, PortNames, Names)
|
|
; convert_other_name(String) = OtherName ->
|
|
Names = [OtherName]
|
|
;
|
|
fail
|
|
).
|
|
|
|
:- pred wrap_port(trace_port::in, trace_suppress_item::out) is det.
|
|
|
|
wrap_port(Port, port(Port)).
|
|
|
|
% If this is modified, then the corresponding code in
|
|
% runtime/mercury_stack_layout.h needs to be updated.
|
|
trace_level_rep(none) = "MR_TRACE_LEVEL_NONE".
|
|
trace_level_rep(shallow) = "MR_TRACE_LEVEL_SHALLOW".
|
|
trace_level_rep(deep) = "MR_TRACE_LEVEL_DEEP".
|
|
trace_level_rep(decl) = "MR_TRACE_LEVEL_DECL".
|
|
trace_level_rep(decl_rep) = "MR_TRACE_LEVEL_DECL_REP".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type port_category
|
|
---> interface % The events that describe the interface of a
|
|
% procedure with its callers.
|
|
; internal % The events inside each procedure that were
|
|
% present in the initial procedural debugger.
|
|
; context. % The events inside each procedure that we
|
|
% added because the declarative debugger needs
|
|
% to know when (potentially) negated contexts
|
|
% start and end.
|
|
|
|
:- func trace_port_category(trace_port) = port_category.
|
|
|
|
trace_port_category(call) = interface.
|
|
trace_port_category(exit) = interface.
|
|
trace_port_category(fail) = interface.
|
|
trace_port_category(redo) = interface.
|
|
trace_port_category(exception) = interface.
|
|
trace_port_category(ite_cond) = context.
|
|
trace_port_category(ite_then) = internal.
|
|
trace_port_category(ite_else) = internal.
|
|
trace_port_category(neg_enter) = context.
|
|
trace_port_category(neg_success) = context.
|
|
trace_port_category(neg_failure) = context.
|
|
trace_port_category(switch) = internal.
|
|
trace_port_category(disj) = internal.
|
|
trace_port_category(nondet_pragma_first) = internal.
|
|
trace_port_category(nondet_pragma_later) = internal.
|
|
|
|
:- func trace_level_port_categories(trace_level) = list(port_category).
|
|
|
|
trace_level_port_categories(none) = [].
|
|
trace_level_port_categories(shallow) = [interface].
|
|
trace_level_port_categories(deep) = [interface, internal].
|
|
trace_level_port_categories(decl) = [interface, internal, context].
|
|
trace_level_port_categories(decl_rep) = [interface, internal, context].
|
|
|
|
:- func trace_level_allows_port_suppression(trace_level) = bool.
|
|
|
|
trace_level_allows_port_suppression(none) = no. % no ports exist
|
|
trace_level_allows_port_suppression(shallow) = yes.
|
|
trace_level_allows_port_suppression(deep) = yes.
|
|
trace_level_allows_port_suppression(decl) = no.
|
|
trace_level_allows_port_suppression(decl_rep) = no.
|
|
|
|
trace_needs_port(TraceLevel, TraceSuppressItems, Port) = NeedsPort :-
|
|
(
|
|
trace_port_category(Port) = Category,
|
|
list__member(Category,
|
|
trace_level_port_categories(TraceLevel)),
|
|
\+ (
|
|
trace_level_allows_port_suppression(TraceLevel) = yes,
|
|
set__member(port(Port), TraceSuppressItems)
|
|
)
|
|
->
|
|
NeedsPort = yes
|
|
;
|
|
NeedsPort = no
|
|
).
|