[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