mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
743 lines
28 KiB
Mathematica
743 lines
28 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2000-2008, 2011-2012 The University of Melbourne.
|
|
% Copyright (C) 2014-2015, 2019-2020, 2022, 2024 The Mercury team.
|
|
% 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.
|
|
%
|
|
% In most cases the trace level we want to apply to a procedure (which is its
|
|
% effective trace level) is the same as the global trace level. However, if the
|
|
% global trace level is shallow, then we optimize the handling of procedures
|
|
% that cannot be called from deep traced contexts. If a procedure is neither
|
|
% exported nor has its address taken, then it can only be called from other
|
|
% procedures in its module. If the module is shallow traced, this guarantees
|
|
% that we will never get any events from the procedure, so there is no point
|
|
% in including any tracing code in it in the first place. We therefore make
|
|
% its effective trace level "none" for must purposes (the purposes whose
|
|
% functions test effective trace levels). Apart from avoiding the overhead
|
|
% of calls to MR_trace, this also allows the code generator to preserve tail
|
|
% recursion optimization. However, we continue to generate the data structures
|
|
% that enable the debugger to walk the stack for such procedures. We accomplish
|
|
% this by making the relevant test work on the global trace level, not
|
|
% effective trace levels. Most of the other functions defined in this module
|
|
% convert the given (global) trace level into the effective trace level of
|
|
% the relevant procedure before calculating their result.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module libs.trace_params.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
|
|
:- import_module bool.
|
|
:- import_module maybe.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The global trace level for a module.
|
|
%
|
|
:- type trace_level.
|
|
|
|
% The effective trace level for a procedure.
|
|
%
|
|
:- type eff_trace_level.
|
|
|
|
% There are some parts of the functionality of the debugger that are
|
|
% enabled by default, but which are not always strictly necessary,
|
|
% and can be suppressed. Values of this type specify exactly what parts
|
|
% should be suppressed.
|
|
%
|
|
:- type trace_suppress_items.
|
|
|
|
% The string should be the value of the --trace-level option;
|
|
% two bools should be the values of the `--require-tracing' and
|
|
% `--decl-debug' grade options.
|
|
%
|
|
% If the string is an acceptable trace level in the specified kinds of
|
|
% grades, return yes wrapper around the trace level.
|
|
%
|
|
% If the string is an known trace level that happens not to be
|
|
% acceptable in the specified kinds of grades, return no.
|
|
%
|
|
% If the string is not known trace level, fail.
|
|
%
|
|
:- pred convert_trace_level(string::in, bool::in, bool::in,
|
|
maybe(trace_level)::out) is semidet.
|
|
|
|
:- pred convert_trace_suppress(string::in, trace_suppress_items::out)
|
|
is semidet.
|
|
:- func default_trace_suppress = trace_suppress_items.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func eff_trace_level_for_proc(module_info, pred_info, proc_info,
|
|
trace_level) = eff_trace_level.
|
|
|
|
% Given a trace level for a module, return the trace level we should use
|
|
% for compiler-generated unify, index and compare predicates.
|
|
%
|
|
:- func trace_level_for_unify_compare(trace_level) = trace_level.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func trace_level_none = trace_level.
|
|
:- func eff_trace_level_none = eff_trace_level.
|
|
|
|
:- func at_least_at_shallow(eff_trace_level) = bool.
|
|
:- func at_least_at_deep(eff_trace_level) = bool.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type maybe_exec_trace_enabled
|
|
---> exec_trace_is_not_enabled
|
|
; exec_trace_is_enabled.
|
|
|
|
% These functions check for various properties of either the global
|
|
% or the effective trace level.
|
|
%
|
|
:- func is_exec_trace_enabled_at_given_trace_level(trace_level) =
|
|
maybe_exec_trace_enabled.
|
|
:- func is_exec_trace_enabled_at_eff_trace_level(eff_trace_level) =
|
|
maybe_exec_trace_enabled.
|
|
:- func eff_trace_level_needs_fail_vars(eff_trace_level) = bool.
|
|
:- func eff_trace_level_needs_fixed_slots(eff_trace_level) = bool.
|
|
:- func eff_trace_level_needs_from_full_slot(eff_trace_level) = bool.
|
|
:- func eff_trace_level_allows_delay_death(eff_trace_level) = bool.
|
|
:- func eff_trace_needs_return_info(eff_trace_level, trace_suppress_items)
|
|
= bool.
|
|
:- func trace_level_allows_tail_rec(trace_level) = bool.
|
|
:- func eff_trace_level_needs_meaningful_var_names(eff_trace_level) = bool.
|
|
:- func eff_trace_needs_all_var_names(eff_trace_level, trace_suppress_items)
|
|
= bool.
|
|
:- func trace_needs_proc_body_reps(trace_level, trace_suppress_items) = bool.
|
|
:- func eff_trace_needs_proc_body_reps(eff_trace_level, trace_suppress_items)
|
|
= bool.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is used to represent the trace level in the module layout
|
|
% and in proc layouts in C code.
|
|
%
|
|
:- func trace_level_rep(trace_level) = string.
|
|
:- func eff_trace_level_rep(eff_trace_level) = string.
|
|
|
|
% This is used to represent the trace level in HLDS dumps.
|
|
%
|
|
:- func eff_trace_level_dump(eff_trace_level) = string.
|
|
|
|
:- func eff_trace_level_needs_port(eff_trace_level, trace_suppress_items,
|
|
trace_port) = bool.
|
|
|
|
:- func encode_suppressed_events(trace_suppress_items) = int.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.pred_name.
|
|
:- import_module hlds.status.
|
|
|
|
:- import_module char.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The trace levels none, shallow, deep and decl_rep correspond to the similarly
|
|
% named options.
|
|
%
|
|
% The effective trace level for a procedure usually corresponds to the
|
|
% global trace level, but can be different in several circumstances.
|
|
%
|
|
% The most obvious one is that non-exported procedures in a module that is
|
|
% being compiled with shallow tracing normally need no tracing at all,
|
|
% and thus their effective trace level is none.
|
|
%
|
|
% However, there is an exception to this exception in the presence of
|
|
% user events.
|
|
%
|
|
% Basic_user is the effective trace level for procedures in shallow traced
|
|
% modules that contain a user defined event. This event requires, among other
|
|
% things, the preservation of variables in the procedure in which it occurs.
|
|
% It also requires the transmission of depth information through all procedures
|
|
% in the module that otherwise wouldn't be traced, which is what trace level
|
|
% basic does.
|
|
%
|
|
% In theory, in a shallow traced module, we could set the trace level of
|
|
% a procedure to none if that procedure is not the ancestor of any procedure
|
|
% containing a user event. However, that test cannot be implemented while
|
|
% retaining separate compilation, given that the call trees of procedures
|
|
% may cross module boundaries, and, in particular, may cross out of this module
|
|
% and then back again through a different entry point.
|
|
|
|
:- type trace_level
|
|
---> none
|
|
; shallow
|
|
; deep
|
|
; decl_rep.
|
|
|
|
:- type eff_trace_level
|
|
---> eff_none
|
|
; eff_basic
|
|
; eff_basic_user
|
|
; eff_shallow
|
|
; eff_deep
|
|
; eff_decl_rep.
|
|
|
|
:- type trace_suppress_item
|
|
---> suppress_port(trace_port)
|
|
; suppress_return_info
|
|
; suppress_all_var_names
|
|
; suppress_proc_body_reps.
|
|
|
|
:- type trace_suppress_items == set(trace_suppress_item).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
convert_trace_level("minimum", no, no, yes(none)).
|
|
convert_trace_level("minimum", yes, no, yes(shallow)).
|
|
convert_trace_level("minimum", _, yes, yes(decl_rep)).
|
|
convert_trace_level("shallow", _, no, yes(shallow)).
|
|
convert_trace_level("shallow", _, yes, no).
|
|
convert_trace_level("deep", _, no, yes(deep)).
|
|
convert_trace_level("deep", _, yes, no).
|
|
convert_trace_level("decl", _, _, yes(decl_rep)).
|
|
convert_trace_level("rep", _, _, yes(decl_rep)).
|
|
convert_trace_level("default", no, no, yes(none)).
|
|
convert_trace_level("default", yes, no, yes(deep)).
|
|
convert_trace_level("default", _, yes, yes(decl_rep)).
|
|
|
|
convert_trace_suppress(SuppressString, SuppressItemSet) :-
|
|
SuppressWords = string.words_separator(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(',').
|
|
|
|
:- pred convert_item_name(string::in, list(trace_suppress_item)::out)
|
|
is semidet.
|
|
|
|
convert_item_name(String, Names) :-
|
|
( if convert_port_name(String, PortName) then
|
|
Names = [suppress_port(PortName)]
|
|
else if convert_port_class_name(String, PortNames) then
|
|
list.map(wrap_port, PortNames, Names)
|
|
else if convert_other_name(String, OtherName) then
|
|
Names = [OtherName]
|
|
else
|
|
fail
|
|
).
|
|
|
|
:- pred wrap_port(trace_port::in, trace_suppress_item::out) is det.
|
|
|
|
wrap_port(Port, suppress_port(Port)).
|
|
|
|
:- pred convert_port_name(string::in, trace_port::out) 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", port_call).
|
|
convert_port_name("exit", port_exit).
|
|
convert_port_name("fail", port_fail).
|
|
convert_port_name("redo", port_redo).
|
|
% convert_port_name("excp", port_exception).
|
|
convert_port_name("exception", port_exception).
|
|
convert_port_name("cond", port_ite_cond).
|
|
convert_port_name("ite_cond", port_ite_cond).
|
|
convert_port_name("then", port_ite_then).
|
|
convert_port_name("ite_then", port_ite_then).
|
|
convert_port_name("else", port_ite_else).
|
|
convert_port_name("ite_else", port_ite_else).
|
|
convert_port_name("nege", port_neg_enter).
|
|
convert_port_name("neg_enter", port_neg_enter).
|
|
convert_port_name("negs", port_neg_success).
|
|
convert_port_name("neg_success", port_neg_success).
|
|
convert_port_name("negf", port_neg_failure).
|
|
convert_port_name("neg_failure", port_neg_failure).
|
|
convert_port_name("swtc", port_switch).
|
|
convert_port_name("switch", port_switch).
|
|
convert_port_name("disj_first", port_disj_first).
|
|
convert_port_name("disj_later", port_disj_later).
|
|
convert_port_name("tail", port_tailrec_call).
|
|
convert_port_name("user", port_user).
|
|
|
|
:- pred convert_port_class_name(string::in, list(trace_port)::out) is semidet.
|
|
|
|
convert_port_class_name("interface", Ports) :-
|
|
Ports = [port_call, port_exit, port_redo, port_fail, port_exception].
|
|
convert_port_class_name("internal", Ports) :-
|
|
Ports = [port_ite_then, port_ite_else, port_switch,
|
|
port_disj_first, port_disj_later].
|
|
convert_port_class_name("context", Ports) :-
|
|
Ports = [port_ite_cond, port_neg_enter, port_neg_success,
|
|
port_neg_failure].
|
|
|
|
:- pred convert_other_name(string::in, trace_suppress_item::out) is semidet.
|
|
|
|
convert_other_name("return", suppress_return_info).
|
|
convert_other_name("return_info", suppress_return_info).
|
|
convert_other_name("names", suppress_all_var_names).
|
|
convert_other_name("all_var_names", suppress_all_var_names).
|
|
convert_other_name("bodies", suppress_proc_body_reps).
|
|
convert_other_name("proc_body_reps", suppress_proc_body_reps).
|
|
|
|
default_trace_suppress = set.init.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
eff_trace_level_for_proc(ModuleInfo, PredInfo, ProcInfo, TraceLevel)
|
|
= EffTraceLevel :-
|
|
( if TraceLevel = none then
|
|
EffTraceLevel = eff_none
|
|
else
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
(
|
|
Origin = origin_proc_transform(ProcTransform, _, _, _),
|
|
( if ProcTransform = proc_transform_io_tabling then
|
|
% Predicates called by a predicate that is I/O tabled
|
|
% should not be traced. If such a predicate were allowed
|
|
% to generate events, then the event numbers of events
|
|
% after the I/O primitive would be different between
|
|
% the first and subsequent (idempotent) executions
|
|
% of the same I/O action.
|
|
EffTraceLevel = eff_none
|
|
else
|
|
EffTraceLevel = usual_eff_trace_level_for_proc(ModuleInfo,
|
|
PredInfo, ProcInfo, TraceLevel)
|
|
)
|
|
;
|
|
Origin = origin_compiler(OriginCompiler),
|
|
( if OriginCompiler = made_for_uci(SpecialPred, _) then
|
|
% Unify and compare predicates can be called from the generic
|
|
% unify and compare predicates in builtin.m, so they can be
|
|
% called from outside this module even if they don't have
|
|
% their address taken.
|
|
%
|
|
% Index predicates can never be called from anywhere except
|
|
% the compare predicate.
|
|
(
|
|
( SpecialPred = spec_pred_unify
|
|
; SpecialPred = spec_pred_compare
|
|
),
|
|
EffTraceLevel = eff_shallow
|
|
;
|
|
SpecialPred = spec_pred_index,
|
|
EffTraceLevel = eff_none
|
|
)
|
|
else
|
|
EffTraceLevel = usual_eff_trace_level_for_proc(ModuleInfo,
|
|
PredInfo, ProcInfo, TraceLevel)
|
|
)
|
|
;
|
|
( Origin = origin_user(_)
|
|
; Origin = origin_pred_transform(_, _, _)
|
|
),
|
|
EffTraceLevel = usual_eff_trace_level_for_proc(ModuleInfo,
|
|
PredInfo, ProcInfo, TraceLevel)
|
|
)
|
|
).
|
|
|
|
:- func usual_eff_trace_level_for_proc(module_info, pred_info, proc_info,
|
|
trace_level) = eff_trace_level.
|
|
|
|
usual_eff_trace_level_for_proc(ModuleInfo, PredInfo, ProcInfo, TraceLevel)
|
|
= EffTraceLevel :-
|
|
(
|
|
TraceLevel = none,
|
|
EffTraceLevel = eff_none
|
|
;
|
|
TraceLevel = shallow,
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
IsExported = pred_status_is_exported(PredStatus),
|
|
proc_info_get_is_address_taken(ProcInfo, AddressTaken),
|
|
( if
|
|
IsExported = no,
|
|
AddressTaken = address_is_not_taken
|
|
then
|
|
proc_info_get_has_user_event(ProcInfo, ProcHasUserEvent),
|
|
(
|
|
ProcHasUserEvent = has_user_event,
|
|
EffTraceLevel = eff_basic_user
|
|
;
|
|
ProcHasUserEvent = has_no_user_event,
|
|
module_info_get_has_user_event(ModuleInfo, ModuleHasUserEvent),
|
|
(
|
|
ModuleHasUserEvent = has_user_event,
|
|
EffTraceLevel = eff_basic
|
|
;
|
|
ModuleHasUserEvent = has_no_user_event,
|
|
EffTraceLevel = eff_none
|
|
)
|
|
)
|
|
else
|
|
EffTraceLevel = eff_shallow
|
|
)
|
|
;
|
|
TraceLevel = deep,
|
|
EffTraceLevel = eff_deep
|
|
;
|
|
TraceLevel = decl_rep,
|
|
EffTraceLevel = eff_decl_rep
|
|
).
|
|
|
|
trace_level_for_unify_compare(none) = none.
|
|
trace_level_for_unify_compare(shallow) = shallow.
|
|
trace_level_for_unify_compare(deep) = shallow.
|
|
trace_level_for_unify_compare(decl_rep) = shallow.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
trace_level_none = none.
|
|
|
|
eff_trace_level_none = eff_none.
|
|
|
|
at_least_at_shallow(eff_none) = no.
|
|
at_least_at_shallow(eff_basic) = no.
|
|
at_least_at_shallow(eff_basic_user) = no.
|
|
at_least_at_shallow(eff_shallow) = yes.
|
|
at_least_at_shallow(eff_deep) = yes.
|
|
at_least_at_shallow(eff_decl_rep) = yes.
|
|
|
|
at_least_at_deep(eff_none) = no.
|
|
at_least_at_deep(eff_basic) = no.
|
|
at_least_at_deep(eff_basic_user) = no.
|
|
at_least_at_deep(eff_shallow) = no.
|
|
at_least_at_deep(eff_deep) = yes.
|
|
at_least_at_deep(eff_decl_rep) = yes.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
is_exec_trace_enabled_at_given_trace_level(TraceLevel) = Enabled :-
|
|
(
|
|
TraceLevel = none,
|
|
Enabled = exec_trace_is_not_enabled
|
|
;
|
|
( TraceLevel = shallow
|
|
; TraceLevel = deep
|
|
; TraceLevel = decl_rep
|
|
),
|
|
Enabled = exec_trace_is_enabled
|
|
).
|
|
|
|
is_exec_trace_enabled_at_eff_trace_level(EffTraceLevel) = Enabled :-
|
|
(
|
|
EffTraceLevel = eff_none,
|
|
Enabled = exec_trace_is_not_enabled
|
|
;
|
|
( EffTraceLevel = eff_basic
|
|
; EffTraceLevel = eff_basic_user
|
|
; EffTraceLevel = eff_shallow
|
|
; EffTraceLevel = eff_deep
|
|
; EffTraceLevel = eff_decl_rep
|
|
),
|
|
Enabled = exec_trace_is_enabled
|
|
).
|
|
|
|
eff_trace_level_needs_fail_vars(EffTraceLevel) = NeedsFailVars :-
|
|
(
|
|
( EffTraceLevel = eff_none
|
|
; EffTraceLevel = eff_basic
|
|
),
|
|
NeedsFailVars = no
|
|
;
|
|
( EffTraceLevel = eff_basic_user
|
|
; EffTraceLevel = eff_shallow
|
|
; EffTraceLevel = eff_deep
|
|
; EffTraceLevel = eff_decl_rep
|
|
),
|
|
NeedsFailVars = yes
|
|
).
|
|
|
|
eff_trace_level_needs_fixed_slots(EffTraceLevel) = NeedsFixedSlots :-
|
|
(
|
|
EffTraceLevel = eff_none,
|
|
NeedsFixedSlots = no
|
|
;
|
|
( EffTraceLevel = eff_basic
|
|
; EffTraceLevel = eff_basic_user
|
|
; EffTraceLevel = eff_shallow
|
|
; EffTraceLevel = eff_deep
|
|
; EffTraceLevel = eff_decl_rep
|
|
),
|
|
NeedsFixedSlots = yes
|
|
).
|
|
|
|
eff_trace_level_needs_from_full_slot(EffTraceLevel) = NeedsFromFullSlot :-
|
|
(
|
|
( EffTraceLevel = eff_none
|
|
; EffTraceLevel = eff_basic
|
|
; EffTraceLevel = eff_basic_user
|
|
; EffTraceLevel = eff_deep
|
|
; EffTraceLevel = eff_decl_rep
|
|
),
|
|
NeedsFromFullSlot = no
|
|
;
|
|
EffTraceLevel = eff_shallow,
|
|
NeedsFromFullSlot = yes
|
|
).
|
|
|
|
eff_trace_level_allows_delay_death(EffTraceLevel) = AllowsDelayDeath :-
|
|
(
|
|
( EffTraceLevel = eff_none
|
|
; EffTraceLevel = eff_basic
|
|
; EffTraceLevel = eff_shallow
|
|
),
|
|
AllowsDelayDeath = no
|
|
;
|
|
( EffTraceLevel = eff_basic_user
|
|
; EffTraceLevel = eff_deep
|
|
; EffTraceLevel = eff_decl_rep
|
|
),
|
|
AllowsDelayDeath = yes
|
|
).
|
|
|
|
eff_trace_needs_return_info(EffTraceLevel, TraceSuppressItems) = NeedReturn :-
|
|
( if
|
|
eff_trace_level_has_return_info(EffTraceLevel) = yes,
|
|
not set.member(suppress_return_info, TraceSuppressItems)
|
|
then
|
|
NeedReturn = yes
|
|
else
|
|
NeedReturn = no
|
|
).
|
|
|
|
trace_level_allows_tail_rec(none) = yes.
|
|
trace_level_allows_tail_rec(shallow) = no.
|
|
trace_level_allows_tail_rec(deep) = yes.
|
|
trace_level_allows_tail_rec(decl_rep) = no.
|
|
|
|
eff_trace_level_needs_meaningful_var_names(eff_none) = no.
|
|
eff_trace_level_needs_meaningful_var_names(eff_basic) = no.
|
|
eff_trace_level_needs_meaningful_var_names(eff_basic_user) = yes.
|
|
eff_trace_level_needs_meaningful_var_names(eff_shallow) = no.
|
|
eff_trace_level_needs_meaningful_var_names(eff_deep) = yes.
|
|
eff_trace_level_needs_meaningful_var_names(eff_decl_rep) = yes.
|
|
|
|
eff_trace_needs_all_var_names(EffTraceLevel, TraceSuppressItems) = NeedNames :-
|
|
( if
|
|
eff_trace_level_has_all_var_names(EffTraceLevel) = yes,
|
|
not set.member(suppress_all_var_names, TraceSuppressItems)
|
|
then
|
|
NeedNames = yes
|
|
else
|
|
NeedNames = no
|
|
).
|
|
|
|
trace_needs_proc_body_reps(TraceLevel, TraceSuppressItems) = NeedBody :-
|
|
( if
|
|
trace_level_has_proc_body_reps(TraceLevel) = yes,
|
|
not set.member(suppress_proc_body_reps, TraceSuppressItems)
|
|
then
|
|
NeedBody = yes
|
|
else
|
|
NeedBody = no
|
|
).
|
|
|
|
eff_trace_needs_proc_body_reps(EffTraceLevel, TraceSuppressItems) = NeedBody :-
|
|
( if
|
|
eff_trace_level_has_proc_body_reps(EffTraceLevel) = yes,
|
|
not set.member(suppress_proc_body_reps, TraceSuppressItems)
|
|
then
|
|
NeedBody = yes
|
|
else
|
|
NeedBody = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func eff_trace_level_has_return_info(eff_trace_level) = bool.
|
|
|
|
eff_trace_level_has_return_info(eff_none) = no.
|
|
eff_trace_level_has_return_info(eff_basic) = yes.
|
|
eff_trace_level_has_return_info(eff_basic_user) = yes.
|
|
eff_trace_level_has_return_info(eff_shallow) = yes.
|
|
eff_trace_level_has_return_info(eff_deep) = yes.
|
|
eff_trace_level_has_return_info(eff_decl_rep) = yes.
|
|
|
|
:- func eff_trace_level_has_all_var_names(eff_trace_level) = bool.
|
|
|
|
eff_trace_level_has_all_var_names(eff_none) = no.
|
|
eff_trace_level_has_all_var_names(eff_basic) = no.
|
|
eff_trace_level_has_all_var_names(eff_basic_user) = no.
|
|
eff_trace_level_has_all_var_names(eff_shallow) = no.
|
|
eff_trace_level_has_all_var_names(eff_deep) = no.
|
|
eff_trace_level_has_all_var_names(eff_decl_rep) = yes.
|
|
|
|
:- func trace_level_has_proc_body_reps(trace_level) = bool.
|
|
|
|
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_rep) = yes.
|
|
|
|
:- func eff_trace_level_has_proc_body_reps(eff_trace_level) = bool.
|
|
|
|
eff_trace_level_has_proc_body_reps(eff_none) = no.
|
|
eff_trace_level_has_proc_body_reps(eff_basic) = no.
|
|
eff_trace_level_has_proc_body_reps(eff_basic_user) = no.
|
|
eff_trace_level_has_proc_body_reps(eff_shallow) = no.
|
|
eff_trace_level_has_proc_body_reps(eff_deep) = no.
|
|
eff_trace_level_has_proc_body_reps(eff_decl_rep) = yes.
|
|
|
|
% If this is modified, then the corresponding code below
|
|
% and 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_rep) = "MR_TRACE_LEVEL_DECL_REP".
|
|
|
|
% If this is modified, then the corresponding code above
|
|
% and in runtime/mercury_stack_layout.h needs to be updated.
|
|
eff_trace_level_rep(eff_none) = "MR_TRACE_LEVEL_NONE".
|
|
eff_trace_level_rep(eff_basic) = "MR_TRACE_LEVEL_BASIC".
|
|
eff_trace_level_rep(eff_basic_user) = "MR_TRACE_LEVEL_BASIC_USER".
|
|
eff_trace_level_rep(eff_shallow) = "MR_TRACE_LEVEL_SHALLOW".
|
|
eff_trace_level_rep(eff_deep) = "MR_TRACE_LEVEL_DEEP".
|
|
eff_trace_level_rep(eff_decl_rep) = "MR_TRACE_LEVEL_DECL_REP".
|
|
|
|
eff_trace_level_dump(eff_none) = "none".
|
|
eff_trace_level_dump(eff_basic) = "basic".
|
|
eff_trace_level_dump(eff_basic_user) = "basic_user".
|
|
eff_trace_level_dump(eff_shallow) = "shallow".
|
|
eff_trace_level_dump(eff_deep) = "deep".
|
|
eff_trace_level_dump(eff_decl_rep) = "decl_rep".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type port_category
|
|
---> port_cat_interface
|
|
% The events that describe the interface of a procedure
|
|
% with its callers.
|
|
|
|
; port_cat_internal
|
|
% The events inside each procedure that were present
|
|
% in the initial procedural debugger.
|
|
|
|
; port_cat_context
|
|
% The events inside each procedure that we added because
|
|
% the declarative debugger needs to know when (potentially)
|
|
% negated contexts start and end.
|
|
|
|
; port_cat_user.
|
|
% User defined events.
|
|
|
|
:- func trace_port_category(trace_port) = port_category.
|
|
|
|
trace_port_category(port_call) = port_cat_interface.
|
|
trace_port_category(port_exit) = port_cat_interface.
|
|
trace_port_category(port_fail) = port_cat_interface.
|
|
trace_port_category(port_redo) = port_cat_interface.
|
|
trace_port_category(port_exception) = port_cat_interface.
|
|
trace_port_category(port_ite_cond) = port_cat_context.
|
|
trace_port_category(port_ite_then) = port_cat_internal.
|
|
trace_port_category(port_ite_else) = port_cat_internal.
|
|
trace_port_category(port_neg_enter) = port_cat_context.
|
|
trace_port_category(port_neg_success) = port_cat_context.
|
|
trace_port_category(port_neg_failure) = port_cat_context.
|
|
trace_port_category(port_switch) = port_cat_internal.
|
|
trace_port_category(port_disj_first) = port_cat_internal.
|
|
trace_port_category(port_disj_later) = port_cat_internal.
|
|
trace_port_category(port_tailrec_call) = port_cat_interface.
|
|
trace_port_category(port_user) = port_cat_user.
|
|
|
|
:- func eff_trace_level_port_categories(eff_trace_level) = list(port_category).
|
|
|
|
eff_trace_level_port_categories(eff_none) = [].
|
|
eff_trace_level_port_categories(eff_basic) = [].
|
|
eff_trace_level_port_categories(eff_basic_user) = [port_cat_user].
|
|
eff_trace_level_port_categories(eff_shallow) = [port_cat_interface].
|
|
eff_trace_level_port_categories(eff_deep) =
|
|
[port_cat_interface, port_cat_internal, port_cat_context, port_cat_user].
|
|
eff_trace_level_port_categories(eff_decl_rep) =
|
|
[port_cat_interface, port_cat_internal, port_cat_context, port_cat_user].
|
|
|
|
:- func eff_trace_level_allows_port_suppression(eff_trace_level) = bool.
|
|
|
|
eff_trace_level_allows_port_suppression(eff_none) = no. % no ports exist
|
|
eff_trace_level_allows_port_suppression(eff_basic) = yes.
|
|
eff_trace_level_allows_port_suppression(eff_basic_user) = yes.
|
|
eff_trace_level_allows_port_suppression(eff_shallow) = yes.
|
|
eff_trace_level_allows_port_suppression(eff_deep) = yes.
|
|
eff_trace_level_allows_port_suppression(eff_decl_rep) = no.
|
|
|
|
eff_trace_level_needs_port(EffTraceLevel, TraceSuppressItems, Port)
|
|
= NeedsPort :-
|
|
( if
|
|
trace_port_category(Port) = Category,
|
|
list.member(Category, eff_trace_level_port_categories(EffTraceLevel)),
|
|
not (
|
|
eff_trace_level_allows_port_suppression(EffTraceLevel) = yes,
|
|
set.member(suppress_port(Port), TraceSuppressItems)
|
|
)
|
|
then
|
|
NeedsPort = yes
|
|
else
|
|
NeedsPort = no
|
|
).
|
|
|
|
encode_suppressed_events(SuppressedEvents) = SuppressedEventsInt :-
|
|
set.fold(maybe_add_suppressed_event, SuppressedEvents,
|
|
0, SuppressedEventsInt).
|
|
|
|
:- pred maybe_add_suppressed_event(trace_suppress_item::in, int::in, int::out)
|
|
is det.
|
|
|
|
maybe_add_suppressed_event(SuppressItem, SuppressedEventsInt0,
|
|
SuppressedEventsInt) :-
|
|
(
|
|
SuppressItem = suppress_port(Port),
|
|
SuppressedEventsInt = SuppressedEventsInt0 \/ (1 << port_number(Port))
|
|
;
|
|
( SuppressItem = suppress_return_info
|
|
; SuppressItem = suppress_all_var_names
|
|
; SuppressItem = suppress_proc_body_reps
|
|
),
|
|
SuppressedEventsInt = SuppressedEventsInt0
|
|
).
|
|
|
|
:- func port_number(trace_port) = int.
|
|
|
|
port_number(port_call) = 0.
|
|
port_number(port_exit) = 1.
|
|
port_number(port_redo) = 2.
|
|
port_number(port_fail) = 3.
|
|
port_number(port_tailrec_call) = 4.
|
|
port_number(port_exception) = 5.
|
|
port_number(port_ite_cond) = 6.
|
|
port_number(port_ite_then) = 7.
|
|
port_number(port_ite_else) = 8.
|
|
port_number(port_neg_enter) = 9.
|
|
port_number(port_neg_success) = 10.
|
|
port_number(port_neg_failure) = 11.
|
|
port_number(port_disj_first) = 12.
|
|
port_number(port_disj_later) = 13.
|
|
port_number(port_switch) = 14.
|
|
port_number(port_user) = 15.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module libs.trace_params.
|
|
%-----------------------------------------------------------------------------%
|