[m-rev.] for review: allow tracking of output arguments of builtin_catch
Ian MacLarty
maclarty at cs.mu.OZ.AU
Sat Dec 10 07:44:46 AEDT 2005
For review by anyone.
Estimated hours taken: 8
Branches: main
Allow tracking of output subterms through builtin_catch.
browser/declarative_tree.m:
Handle catch_impl as a special case when tracking an output
argument.
tests/debugger/declarative/track_through_catch.exp:
tests/debugger/declarative/track_through_catch.inp:
test tracking an output subterm of exception.try.
trace/mercury_trace.c:
trace/mercury_trace_util.c:
trace/mercury_trace_util.h:
Do not unwind stack frames to builtin_catch, since builtin_catch
has no CALL event to retry to, instead rewind to the parent stack
frame (catch_impl).
Index: browser/declarative_tree.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_tree.m,v
retrieving revision 1.36
diff -u -r1.36 declarative_tree.m
--- browser/declarative_tree.m 8 Dec 2005 20:38:44 -0000 1.36
+++ browser/declarative_tree.m 9 Dec 2005 20:37:48 -0000
@@ -49,6 +49,7 @@
:- import_module mdb.declarative_debugger.
:- import_module mdb.io_action.
+:- import_module mdb.term_rep.
:- import_module mdb.util.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.program_representation.
@@ -838,22 +839,11 @@
;
MaybeProcRep = yes(ProcRep),
(
- %
- % catch_impl's body is a single call to
- % builtin_catch. builtin_catch doesn't
- % generate any events, so we need to
- % handle catch_impl specially.
- % If the subterm being tracked is an
- % input to builtin_catch then we know the
- % origin will be in the first argument of
- % catch_impl, because builtin_catch is
- % only called from catch_impl.
- %
- proc_rep_is_catch_impl(ProcRep),
- StartLoc = parent_goal(_, _)
+ trace_dependency_special_case(Store, ProcRep,
+ Ref, StartLoc, ArgNum, TermPath,
+ NodeId, Origin0)
->
- Origin = input(user_head_var(1),
- [ArgNum | TermPath])
+ Origin = Origin0
;
trace_dependency_in_proc_rep(Store, TermPath,
StartLoc, ArgNum, TotalArgs, NodeId,
@@ -868,6 +858,65 @@
Mode = subterm_out
).
+ % trace_dependency_special_case handles special cases not
+ % handled by the usual subterm dependency tracking algorithm,
+ % At the moment it handles tracking of subterms through catch_impl.
+ %
+:- pred trace_dependency_special_case(S::in, proc_rep::in, R::in,
+ start_loc(R)::in, int::in, term_path::in, R::in,
+ subterm_origin(edt_node(R))::out) is semidet
+ <= annotated_trace(S, R).
+
+trace_dependency_special_case(Store, ProcRep, Ref, StartLoc, ArgNum, TermPath,
+ NodeId, Origin) :-
+ %
+ % catch_impl's body is a single call to
+ % builtin_catch. builtin_catch doesn't
+ % generate any events, so we need to
+ % handle catch_impl specially.
+ %
+ proc_rep_is_catch_impl(ProcRep),
+ (
+ StartLoc = parent_goal(_, _),
+ %
+ % The subterm being tracked is an
+ % input to builtin_catch so we know the
+ % origin will be in the first argument of
+ % catch_impl, because builtin_catch is
+ % only called from catch_impl.
+ %
+ Origin = input(user_head_var(1),
+ [ArgNum | TermPath])
+ ;
+ StartLoc = cur_goal,
+ %
+ % The subterm being tracked is an output of
+ % catch_impl so we know its origin will be the output
+ % of the closure passed to try.
+ % If the closure succeeded, then we continue to track the
+ % subterm in the child call to
+ % exception.wrap_success_or_failure, otherwise we stop tracking
+ % at the catch_impl. XXX In future we should track exception
+ % values to the throw that created them.
+ %
+ exit_node_from_id(Store, Ref, ExitNode),
+ ExitAtom = get_trace_exit_atom(ExitNode),
+ ExitAtom = atom(_, Args),
+ list.index1_det(Args, ArgNum, TryResultArgInfo),
+ TryResultArgInfo = arg_info(_, _, yes(TryResultRep)),
+ rep_to_univ(TryResultRep, TryResultUniv),
+ univ_value(TryResultUniv) = TryResult,
+ std_util.deconstruct(TryResult, Functor, _, _),
+ (
+ Functor = "succeeded"
+ ->
+ Origin = output(dynamic(NodeId),
+ any_head_var_from_back(1), TermPath)
+ ;
+ Origin = primitive_op("exception.m", 0, builtin_call)
+ )
+ ).
+
:- pred trace_dependency_in_proc_rep(S::in, term_path::in,
start_loc(R)::in, int::in, int::in, R::in, maybe(goal_path)::in,
proc_rep::in, subterm_origin(edt_node(R))::out)
@@ -1772,9 +1821,17 @@
traverse_call(BoundVars, File, Line, Args, MaybeNodeId, Prims,
Var0, TermPath0, Store, ProcRep, Origin)
;
- AtomicGoal = plain_call_rep(_, _, Args),
- traverse_call(BoundVars, File, Line, Args, MaybeNodeId,
- Prims, Var0, TermPath0, Store, ProcRep, Origin)
+ AtomicGoal = plain_call_rep(Module, Name, Args),
+ (
+ list.member(Var0, BoundVars),
+ plain_call_is_special_case(Module, Name, Args, NewVar)
+ ->
+ traverse_primitives(Prims, NewVar, TermPath0, Store,
+ ProcRep, Origin)
+ ;
+ traverse_call(BoundVars, File, Line, Args, MaybeNodeId,
+ Prims, Var0, TermPath0, Store, ProcRep, Origin)
+ )
;
AtomicGoal = builtin_call_rep(_, _, _),
( list.member(Var0, BoundVars) ->
@@ -1785,6 +1842,23 @@
)
).
+ % Some foreign calls, such as casts, are handled specially
+ % to improve the accuracy of the subterm dependency tracking
+ % algorithm.
+ %
+:- pred plain_call_is_special_case(string::in, string::in, list(var_rep)::in,
+ var_rep::out) is semidet.
+
+plain_call_is_special_case(Module, Name, Args, NewVar) :-
+ %
+ % std_util.cc_multi_equal is the same as a unification for the
+ % purposes of subterm dependency tracking.
+ %
+ Module = "std_util",
+ Name = "cc_multi_equal",
+ list.length(Args, 3),
+ index1_det(Args, 2) = NewVar.
+
:- type plain_call_info
---> plain_call_info(
file_name :: string,
Index: tests/debugger/declarative/track_through_catch.exp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/declarative/track_through_catch.exp,v
retrieving revision 1.1
diff -u -r1.1 track_through_catch.exp
--- tests/debugger/declarative/track_through_catch.exp 8 Dec 2005 20:38:46 -0000 1.1
+++ tests/debugger/declarative/track_through_catch.exp 9 Dec 2005 20:21:28 -0000
@@ -4,18 +4,37 @@
mdb> untrust 0
mdb> table_io start
I/O tabling started.
-mdb> break r
- 0: + stop interface pred track_through_catch.r/2-0 (det)
+mdb> break try
+Ambiguous procedure specification. The matches are:
+0: pred exception.try/3-3 (cc_multi)
+1: pred exception.try/3-2 (cc_multi)
+2: pred exception.try/3-1 (cc_multi)
+3: pred exception.try/3-0 (cc_multi)
+4: pred exception.try/2-3 (cc_multi)
+5: pred exception.try/2-2 (cc_multi)
+6: pred exception.try/2-1 (cc_multi)
+7: pred exception.try/2-0 (cc_multi)
+
+Which do you want to put a breakpoint on (0-7 or *)? *
+ 0: + stop interface pred exception.try/3-3 (cc_multi)
+ 1: + stop interface pred exception.try/3-2 (cc_multi)
+ 2: + stop interface pred exception.try/3-1 (cc_multi)
+ 3: + stop interface pred exception.try/3-0 (cc_multi)
+ 4: + stop interface pred exception.try/2-3 (cc_multi)
+ 5: + stop interface pred exception.try/2-2 (cc_multi)
+ 6: + stop interface pred exception.try/2-1 (cc_multi)
+ 7: + stop interface pred exception.try/2-0 (cc_multi)
mdb> c
- E2: C2 CALL pred track_through_catch.r/2-0 (det) track_through_catch.m:30 (track_through_catch.m:26)
-mdb> delete *
- 0: E stop interface pred track_through_catch.r/2-0 (det)
+ E2: C2 CALL pred exception.try/2-0 (cc_multi) exception.m:470 (track_through_catch.m:15)
mdb> f
- E3: C2 EXIT pred track_through_catch.r/2-0 (det) track_through_catch.m:30 (track_through_catch.m:26)
+ E3: C3 CALL pred exception.try/3-0 (cc_multi) exception.m:474 (exception.m:472)
+ E4: C3 EXIT pred exception.try/3-0 (cc_multi) exception.m:474 (exception.m:472)
+ E5: C2 EXIT pred exception.try/2-0 (cc_multi) exception.m:470 (track_through_catch.m:15)
mdb> dd
-r(2, 2)
-Valid? b 1
-browser> track -a
+try(q(2), succeeded(2))
+Valid? b 2
+browser> cd 1
+browser> track
succeeded(2)
p(2)
Valid? info
@@ -26,5 +45,5 @@
(track_through_catch.m:21). The path to the subterm in the atom is 1.
dd> quit
Diagnosis aborted.
- E3: C2 EXIT pred track_through_catch.r/2-0 (det) track_through_catch.m:30 (track_through_catch.m:26)
+ E5: C2 EXIT pred exception.try/2-0 (cc_multi) exception.m:470 (track_through_catch.m:15)
mdb> quit -y
Index: tests/debugger/declarative/track_through_catch.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/declarative/track_through_catch.inp,v
retrieving revision 1.1
diff -u -r1.1 track_through_catch.inp
--- tests/debugger/declarative/track_through_catch.inp 8 Dec 2005 20:38:46 -0000 1.1
+++ tests/debugger/declarative/track_through_catch.inp 9 Dec 2005 20:19:06 -0000
@@ -2,13 +2,14 @@
echo on
untrust 0
table_io start
-break r
+break try
+*
c
-delete *
f
dd
-b 1
-track -a
+b 2
+cd 1
+track
info
quit
quit -y
Index: trace/mercury_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace.c,v
retrieving revision 1.92
diff -u -r1.92 mercury_trace.c
--- trace/mercury_trace.c 7 Dec 2005 11:12:36 -0000 1.92
+++ trace/mercury_trace.c 9 Dec 2005 18:59:19 -0000
@@ -1219,6 +1219,17 @@
#endif
level_layout = return_label_layout->MR_sll_entry;
+
+ /*
+ ** Don't unwind to builtin_catch, because builtin_catch has
+ ** no CALL event, even though it has a stack frame.
+ */
+ if ((i == ancestor_level - 1) &&
+ MR_trace_proc_layout_is_builtin_catch(level_layout))
+ {
+ i--;
+ }
+
*problem = MR_undo_updates_of_maxfr(level_layout,
*base_sp_ptr, *base_curfr_ptr, base_maxfr_ptr);
Index: trace/mercury_trace_util.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_util.c,v
retrieving revision 1.16
diff -u -r1.16 mercury_trace_util.c
--- trace/mercury_trace_util.c 1 Sep 2005 07:37:26 -0000 1.16
+++ trace/mercury_trace_util.c 9 Dec 2005 17:44:38 -0000
@@ -188,3 +188,22 @@
(long) MR_trace_call_depth);
#endif
}
+
+MR_bool
+MR_trace_proc_layout_is_builtin_catch(const MR_Proc_Layout *layout)
+{
+ const MR_User_Proc_Id *user;
+
+ if (MR_PROC_LAYOUT_HAS_PROC_ID(layout)) {
+ if (! MR_PROC_LAYOUT_IS_UCI(layout)) {
+ user = &layout->MR_sle_user;
+ if (MR_streq(user->MR_user_decl_module, "exception") &&
+ MR_streq(user->MR_user_name, "builtin_catch") &&
+ (user->MR_user_arity == 3))
+ {
+ return MR_TRUE;
+ }
+ }
+ }
+ return MR_FALSE;
+}
Index: trace/mercury_trace_util.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_util.h,v
retrieving revision 1.12
diff -u -r1.12 mercury_trace_util.h
--- trace/mercury_trace_util.h 1 Sep 2005 07:37:26 -0000 1.12
+++ trace/mercury_trace_util.h 9 Dec 2005 16:14:52 -0000
@@ -69,4 +69,12 @@
extern void MR_print_r_regs(FILE *fp, MR_Word *saved_regs);
extern void MR_print_debug_vars(FILE *fp, MR_Event_Details *event_details);
+/*
+** This function returns MR_TRUE if the layout is for exception.builtin_catch
+** and false otherwise. Because builtin_catch creates a stack frame, but no
+** events, it must be handled specially by some parts of the debugger.
+*/
+extern MR_bool MR_trace_proc_layout_is_builtin_catch(
+ const MR_Proc_Layout *layout);
+
#endif /* MERCURY_TRACE_UTIL_H */
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list