[m-dev.] for review: direct retries

Zoltan Somogyi zs at cs.mu.OZ.AU
Thu Jan 20 17:50:24 AEDT 2000


The debugger's retry command at the moment works only from a final port for
the call to be retried, the reason being that the RTTI does not have the
information required to make sure that the state of the stacks is reset
correctly. This change adds the required info to the RTTI and thus enables
direct retries from the middle of calls.

The information added has two components. First, if a procedure that lives on
the nondet stack allocates any temporary nondet stack frames, then it must
record the old value of maxfr in a stack slot so that retry can restore it.
Second, if a procedure is tabled, then it must record the call table tip node
corresponding to the actual input arguments, so we can reset this node to
uninitialized (if we don't, then the retried call will find the active call
marker and report an infinite loop error).

The support for retries across minimal model calls is not finished yet;
that waits for fixes to minimal model tabling itself. However, such retries
do grossly wrong things at the moment; this change is a definite improvement.

runtime/mercury_stack_layout.h:
	Add three new fields to proc layouts: the numbers of the stack slots
	(if any) storing the saved maxfr and the call table tip, and a
	representation of the procedure's evaluation method.

compiler/stack_layout.m:
	Generate the three new fields.

compiler/continuation_info.m:
	Record the information about the new fields for later use by
	stack_layout.m.

compiler/trace.m:
compiler/live_vars.m:
	Reserve the fixed stack slot for the saved maxfr if necessary,
	and if the call table tip node is needed, make sure that the variable
	holding its address is allocated a low-numbered stack slot (otherwise,
	its number may not fit into the MR_int_least8_t field in the
	proc_layout).

compiler/trace.m:
	If necessary, fill in the saved maxfr slot.

	If necessary, initialize the call table tip slot.

compiler/hlds_goal.m:
	Add a goal feature which marks its goal as defining the variable
	representing the call table tip node.

compiler/hlds_pred.m:
compiler/hlds_out.m:
	Add a field to proc_infos which records which variable, if any, holds
	the call table tip node.

compiler/table_gen.m:
	Put this feature on the appropriate goal.

	Also, rename a predicate to make it reflect its purpose better.

compiler/code_gen.m:
	Generate code to put the call table tip variable in its stack slot
	immediately after it has been generated.

	Add a sanity check to ensure that if a procedure that lives on the det
	stack can create a temporary nondet frame, and debugging is enabled,
	then it did have a stack slot reserved for the saved maxfr.

compiler/code_util.m:
	Add a predicate to make a conservative prediction of whether a
	procedure may allocate a temporary nondet stack frame. We cannot
	just generate the code and see, because the code generator needs to
	know which variables live in which stack slots, and we cannot decide
	that until we know whether we need a stack slot for the saved value of
	maxfr.

	Make an unrelated predicate semidet procedure use a det helper, in
	order to make it more robust in the face of changes to the HLDS
	(e.g. it was missing code for handling bi_implications).

compiler/code_info.m:
	Record whether a procedure has in fact created a temporary nondet stack
	frame.

compiler/handle_options.m:
	Disable hijacks if debugging is enabled.

compiler/optimize.m:
	Trivial changes to conform to changes in data structures.

trace/mercury_trace.[ch]:
	Reimplement MR_trace_retry to allow retries from the middle.
	If the stack segment being retried over contains minimal model
	procedures, we must still arrange to skip to the end of the retried
	call. If this call is a minimal model generator, skipping to just any
	final port is not sufficient to guarantee correctness on retry; to
	ensure that subgoal is complete, we must skip to a fail port.

trace/mercury_trace.[ch]:
trace/mercury_trace_internal.c:
	Implement a debugger command, "fail", which skips to the fail port or
	the exception port of the specified ancestor. Since only model_non
	procedures are guaranteed eventually to get to such a port, this
	command reports an error if the specified call is not model_non.

trace/mercury_trace_internal.c:
trace/mercury_trace_external.c:
trace/mercury_trace_declarative.c:
	Use the new implementation of retries. At the moment, only the
	internal debugger implements the full functionality. The declarative
	debugger issues retry commands only from situations where the missing
	functionality is not (yet) needed. The external debugger may need
	updating by Erwan.

doc/user_guide.texi:
	Document the new "fail" command.

	Update the documentation of the "finish" command.

tests/debugger/retry.{m,inp,exp,exp2}:
	A new test case for exercising retry.

tests/debugger/Mmakefile:
	Enable the new test case.

tests/debugger/mdb_command_test.inp:
	Test the documentation of the fail command.

Zoltan.

cvs diff: Diffing .
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_gen.m,v
retrieving revision 1.71
diff -u -b -r1.71 code_gen.m
--- compiler/code_gen.m	1999/12/14 04:52:31	1.71
+++ compiler/code_gen.m	2000/01/15 04:46:13
@@ -209,8 +209,8 @@
 		% needed for model_non procedures only if we are doing
 		% execution tracing.
 	code_info__init(SaveSuccip, Globals, PredId, ProcId, ProcInfo,
-		FollowVars, ModuleInfo, CellCount0, OutsideResumePoint,
-		TraceSlotInfo, CodeInfo0),
+		FollowVars, ModuleInfo, CellCount0,
+		OutsideResumePoint, TraceSlotInfo, CodeInfo0),
 
 		% Generate code for the procedure.
 	generate_category_code(CodeModel, Goal, OutsideResumePoint,
@@ -219,6 +219,28 @@
 	code_info__get_max_reg_in_use_at_trace(MaxTraceReg, CodeInfo, _),
 	code_info__get_cell_count(CellCount, CodeInfo, _),
 
+	globals__get_trace_level(Globals, TraceLevel),
+	code_info__get_temp_frame_flag(CreatedTempFrame, CodeInfo, _),
+
+	(
+		TraceLevel \= none,
+		CreatedTempFrame = yes,
+		CodeModel \= model_non
+	->
+			% If tracing is enabled, the procedure lives on
+			% the det stack and the code created any temporary
+			% nondet stack frames, then we must have reserved a
+			% stack slot for storing the value of maxfr; if we
+			% didn't, a retry command in the debugger from a point
+			% in the middle of this procedure will do the wrong
+			% thing.
+		proc_info_get_maxfr_slot_flag(ProcInfo, HaveMaxfrSlot),
+		require(unify(HaveMaxfrSlot, yes),
+			"should have reserved a slot for maxfr, but didn't")
+	;
+		true
+	),
+
 		% Turn the code tree into a list.
 	tree__flatten(CodeTree, FragmentList),
 		% Now the code is a list of code fragments (== list(instr)),
@@ -243,9 +265,10 @@
 		code_info__get_layout_info(InternalMap, CodeInfo, _),
 		code_util__make_local_entry_label(ModuleInfo, PredId, ProcId,
 			no, EntryLabel),
+		proc_info_eval_method(ProcInfo, EvalMethod),
 		ProcLayout = proc_layout_info(EntryLabel, Detism, TotalSlots,
-			MaybeSuccipSlot, MaybeTraceCallLabel, MaxTraceReg,
-			TraceSlotInfo, ForceProcId, InternalMap),
+			MaybeSuccipSlot, EvalMethod, MaybeTraceCallLabel,
+			MaxTraceReg, TraceSlotInfo, ForceProcId, InternalMap),
 		global_data_add_new_proc_layout(GlobalData0,
 			proc(PredId, ProcId), ProcLayout, GlobalData1)
 	;
@@ -271,7 +294,10 @@
 		GlobalData0, GlobalData) :-
 	proc_info_eval_method(ProcInfo, EvalMethod),
 	(
-		EvalMethod \= eval_normal
+		( EvalMethod = eval_loop_check
+		; EvalMethod = eval_memo
+		; EvalMethod = eval_minimal
+		)
 	->
 		code_util__make_proc_label(ModuleInfo, PredId, ProcId,
 			ProcLabel),
@@ -453,7 +479,7 @@
 			% definition would be better than BodyContext.
 		trace__generate_external_event_code(fail, TraceInfo,
 			BodyContext, _, _, TraceFailCode),
-		{ TraceSlotInfo = trace_slot_info(_, _, yes(_)) ->
+		{ TraceSlotInfo = trace_slot_info(_, _, yes(_), _, _) ->
 			DiscardTraceTicketCode = node([
 				discard_ticket - "discard retry ticket"
 			])
@@ -715,7 +741,7 @@
 			])
 		},
 		{
-			TraceSlotInfo = trace_slot_info(_, _, yes(_)),
+			TraceSlotInfo = trace_slot_info(_, _, yes(_), _, _),
 			CodeModel \= model_non
 		->
 			DiscardTraceTicketCode = node([
@@ -852,8 +878,33 @@
 				error("nondet model in det/semidet context")
 			)
 		},
+
+		code_gen__generate_goal_2(Goal, GoalInfo, CodeModel, GoalCode),
 
-		code_gen__generate_goal_2(Goal, GoalInfo, CodeModel, Code),
+			% If the predicate's evaluation method is memo,
+			% loopcheck or minimal model, the goal generated
+			% the variable that represents the call table tip,
+			% *and* tracing is enabled, then we save this variable
+			% to its stack slot. This is necessary to enable
+			% retries across this procedure to reset the call table
+			% entry to uninitialized, effectively removing the
+			% call table entry.
+		(
+			{ goal_info_get_features(GoalInfo, Features) },
+			{ set__member(call_table_gen, Features) },
+			code_info__get_proc_info(ProcInfo),
+			{ proc_info_get_call_table_tip(ProcInfo,
+				MaybeCallTableVar) },
+				% MaybeCallTableVar will be `no' unless
+				% tracing is enabled.
+			{ MaybeCallTableVar = yes(CallTableVar) }
+		->
+			code_info__save_variable_on_stack(CallTableVar,
+				SaveCode),
+			{ Code = tree(GoalCode, SaveCode) }
+		;
+			{ Code = GoalCode }
+		),
 
 			% Make live any variables which subsequent goals
 			% will expect to be live, but were not generated
Index: compiler/code_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.246
diff -u -b -r1.246 code_info.m
--- compiler/code_info.m	1999/12/14 04:52:33	1.246
+++ compiler/code_info.m	2000/01/15 04:46:14
@@ -66,8 +66,8 @@
 		% outermost resumption point, and info about the non-fixed
 		% stack slots used for tracing purposes.
 :- pred code_info__init(bool, globals, pred_id, proc_id, proc_info,
-	follow_vars, module_info, int, resume_point_info,
-	trace_slot_info, code_info).
+	follow_vars, module_info, int, resume_point_info, trace_slot_info,
+	code_info).
 :- mode code_info__init(in, in, in, in, in, in, in, in, out, out, out) is det.
 
 		% Get the globals table.
@@ -149,6 +149,11 @@
 :- pred code_info__set_max_reg_in_use_at_trace(int, code_info, code_info).
 :- mode code_info__set_max_reg_in_use_at_trace(in, in, out) is det.
 
+		% Get the flag which is true iff the procedure has so far
+		% emitted code that creates a temporary nondet stack frame.
+:- pred code_info__get_temp_frame_flag(bool, code_info, code_info).
+:- mode code_info__get_temp_frame_flag(out, in, out) is det.
+
 %---------------------------------------------------------------------------%
 
 :- implementation.
@@ -215,6 +220,9 @@
 	code_info, code_info).
 :- mode code_info__set_non_common_static_data(in, in, out) is det.
 
+:- pred code_info__set_temp_frame_flag(bool, code_info, code_info).
+:- mode code_info__set_temp_frame_flag(in, in, out) is det.
+
 %---------------------------------------------------------------------------%
 
 	% The code_info structure has three groups of fields.
@@ -297,7 +305,7 @@
 				% Static data structures created for this
 				% procedure which do not need to be scanned
 				% by llds_common.
-		int		% At each call to MR_trace, we compute the
+		int,		% At each call to MR_trace, we compute the
 				% highest rN register number that contains
 				% a useful value. This slot contains the
 				% maximum of these highest values. Therefore
@@ -306,6 +314,8 @@
 				% are equal to or smaller than this field.
 				% This slot contains -1 if tracing is not
 				% enabled.
+		bool		% True iff the procedure has created
+				% temporary nondet frames.
 	).
 
 %---------------------------------------------------------------------------%
@@ -340,7 +350,7 @@
 	set__init(Zombies),
 	map__init(LayoutMap),
 	code_info__max_var_slot(StackSlots, VarSlotMax),
-	trace__reserved_slots(ProcInfo, Globals, FixedSlots),
+	trace__reserved_slots(ProcInfo, Globals, FixedSlots, _),
 	int__max(VarSlotMax, FixedSlots, SlotMax),
 	CodeInfo0 = code_info(
 		Globals,
@@ -366,7 +376,8 @@
 		0,
 		TempContentMap,
 		[],
-		-1
+		-1,
+		no
 	),
 	code_info__init_maybe_trace_info(Globals, ModuleInfo, ProcInfo,
 		MaybeFailVars, TraceSlotInfo, CodeInfo0, CodeInfo1),
@@ -381,196 +392,206 @@
 		MaybeFailVars, TraceSlotInfo) -->
 	{ globals__get_trace_level(Globals, TraceLevel) },
 	( { TraceLevel \= none } ->
-		trace__setup(Globals, TraceSlotInfo, TraceInfo),
+		trace__setup(ProcInfo, Globals, TraceSlotInfo, TraceInfo),
 		code_info__set_maybe_trace_info(yes(TraceInfo)),
 		{ trace__fail_vars(ModuleInfo, ProcInfo, FailVars) },
 		{ MaybeFailVars = yes(FailVars) }
 	;
 		{ MaybeFailVars = no },
-		{ TraceSlotInfo = trace_slot_info(no, no, no) }
+		{ TraceSlotInfo = trace_slot_info(no, no, no, no, no) }
 	).
 
 %---------------------------------------------------------------------------%
 
 code_info__get_globals(SA, CI, CI) :-
 	CI  = code_info(SA, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_module_info(SB, CI, CI) :-
 	CI  = code_info(_, SB, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_pred_id(SC, CI, CI) :-
 	CI  = code_info(_, _, SC, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_proc_id(SD, CI, CI) :-
 	CI  = code_info(_, _, _, SD, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_proc_info(SE, CI, CI) :-
 	CI  = code_info(_, _, _, _, SE, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_varset(SF, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, SF, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_var_slot_count(SG, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, SG, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_maybe_trace_info(SH, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, SH,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_forward_live_vars(LA, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		LA, _, _, _, _, _, _, _, _, _, _, _, _, _).
+		LA, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_instmap(LB, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, LB, _, _, _, _, _, _, _, _, _, _, _, _).
+		_, LB, _, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_zombies(LC, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, LC, _, _, _, _, _, _, _, _, _, _, _).
+		_, _, LC, _, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_exprn_info(LD, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, LD, _, _, _, _, _, _, _, _, _, _).
+		_, _, _, LD, _, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_temps_in_use(LE, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, LE, _, _, _, _, _, _, _, _, _).
+		_, _, _, _, LE, _, _, _, _, _, _, _, _, _, _).
 
 code_info__get_fail_info(LF, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, LF, _, _, _, _, _, _, _, _).
+		_, _, _, _, _, LF, _, _, _, _, _, _, _, _, _).
 
 code_info__get_label_count(PA, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, PA, _, _, _, _, _, _, _).
+		_, _, _, _, _, _, PA, _, _, _, _, _, _, _, _).
 
 code_info__get_cell_count(PB, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, PB, _, _, _, _, _, _).
+		_, _, _, _, _, _, _, PB, _, _, _, _, _, _, _).
 
 code_info__get_succip_used(PC, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, PC, _, _, _, _, _).
+		_, _, _, _, _, _, _, _, PC, _, _, _, _, _, _).
 
 code_info__get_layout_info(PD, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, PD, _, _, _, _).
+		_, _, _, _, _, _, _, _, _, PD, _, _, _, _, _).
 
 code_info__get_max_temp_slot_count(PE, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, PE, _, _, _).
+		_, _, _, _, _, _, _, _, _, _, PE, _, _, _, _).
 
 code_info__get_temp_content_map(PF, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, PF, _, _).
+		_, _, _, _, _, _, _, _, _, _, _, PF, _, _, _).
 
 code_info__get_non_common_static_data(PG, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, PG, _).
+		_, _, _, _, _, _, _, _, _, _, _, _, PG, _, _).
 
 code_info__get_max_reg_in_use_at_trace(PH, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _, _, PH, _).
+
+code_info__get_temp_frame_flag(PI, CI, CI) :-
 	CI  = code_info(_, _, _, _, _, _, _, _,
-		_, _, _, _, _, _, _, _, _, _, _, _, _, PH).
+		_, _, _, _, _, _, _, _, _, _, _, _, _, _, PI).
 
 %---------------------------------------------------------------------------%
 
 code_info__set_maybe_trace_info(SH, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, _,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH),
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_forward_live_vars(LA, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		_,  LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH),
+		_,  LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_instmap(LB, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, _,  LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH),
+		LA, _,  LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_zombies(LC, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, _,  LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH),
+		LA, LB, _,  LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_exprn_info(LD, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, _,  LE, LF, PA, PB, PC, PD, PE, PF, PG, PH),
+		LA, LB, LC, _,  LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_temps_in_use(LE, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, _,  LF, PA, PB, PC, PD, PE, PF, PG, PH),
+		LA, LB, LC, LD, _,  LF, PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_fail_info(LF, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, _,  PA, PB, PC, PD, PE, PF, PG, PH),
+		LA, LB, LC, LD, LE, _,  PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_label_count(PA, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, _,  PB, PC, PD, PE, PF, PG, PH),
+		LA, LB, LC, LD, LE, LF, _,  PB, PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_cell_count(PB, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, _,  PC, PD, PE, PF, PG, PH),
+		LA, LB, LC, LD, LE, LF, PA, _,  PC, PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_succip_used(PC, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, _,  PD, PE, PF, PG, PH),
+		LA, LB, LC, LD, LE, LF, PA, PB, _,  PD, PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_layout_info(PD, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, _,  PE, PF, PG, PH),
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, _,  PE, PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_max_temp_slot_count(PE, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, _,  PF, PG, PH),
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, _,  PF, PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_temp_content_map(PF, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, _ , PG, PH),
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, _ , PG, PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_non_common_static_data(PG, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, _ , PH),
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, _ , PH, PI),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__set_max_reg_in_use_at_trace(PH, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, _ , PI),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
+
+code_info__set_temp_frame_flag(PI, CI0, CI) :-
 	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, _ ),
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, _ ),
 	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -964,11 +985,11 @@
 code_info__reset_to_position(position_info(PosCI), CurCI, NextCI) :-
 		% The static fields in PosCI and CurCI should be identical.
 	PosCI  = code_info(_,  _,  _,  _,  _,  _,  _,  _, 
-		LA, LB, LC, LD, LE, LF, _,  _,  _,  _,  _,  _,  _,  _ ),
+		LA, LB, LC, LD, LE, LF, _,  _,  _,  _,  _,  _,  _,  _,  _ ),
 	CurCI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		_,  _,  _,  _,  _,  _,  PA, PB, PC, PD, PE, PF, PG, PH),
+		_,  _,  _,  _,  _,  _,  PA, PB, PC, PD, PE, PF, PG, PH, PI),
 	NextCI = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
-		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH).
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF, PG, PH, PI).
 
 code_info__reset_resume_known(BranchStart) -->
 	{ BranchStart = position_info(BranchStartCI) },
@@ -1995,6 +2016,7 @@
 		mkframe(temp_frame(Kind), Redoip)
 			- Comment
 	]) },
+	code_info__set_temp_frame_flag(yes),
 	code_info__get_fail_info(FailInfo0),
 	{ FailInfo0 = fail_info(ResumePoints, ResumeKnown, _, CondEnv, Allow) },
 	{ FailInfo = fail_info(ResumePoints, ResumeKnown, may_be_different,
Index: compiler/code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_util.m,v
retrieving revision 1.116
diff -u -b -r1.116 code_util.m
--- compiler/code_util.m	2000/01/16 04:34:35	1.116
+++ compiler/code_util.m	2000/01/17 01:47:23
@@ -80,6 +80,9 @@
 :- pred code_util__goal_list_may_allocate_heap(list(hlds_goal)).
 :- mode code_util__goal_list_may_allocate_heap(in) is semidet.
 
+:- pred code_util__goal_may_alloc_temp_frame(hlds_goal).
+:- mode code_util__goal_may_alloc_temp_frame(in) is semidet.
+
 	% Negate a condition.
 	% This is used mostly just to make the generated code more readable.
 
@@ -586,53 +589,160 @@
 	special_pred_name_arity(_, _, PredName, PredArity).
 
 %-----------------------------------------------------------------------------%
+
+code_util__goal_may_allocate_heap(Goal) :-
+	code_util__goal_may_allocate_heap(Goal, yes).
+
+code_util__goal_list_may_allocate_heap(Goals) :-
+	code_util__goal_list_may_allocate_heap(Goals, yes).
+
+:- pred code_util__goal_may_allocate_heap(hlds_goal::in, bool::out) is det.
+
+code_util__goal_may_allocate_heap(Goal - _GoalInfo, May) :-
+	code_util__goal_may_allocate_heap_2(Goal, May).
+
+:- pred code_util__goal_may_allocate_heap_2(hlds_goal_expr::in, bool::out)
+	is det.
+
+code_util__goal_may_allocate_heap_2(generic_call(_, _, _, _), yes).
+code_util__goal_may_allocate_heap_2(call(_, _, _, Builtin, _, _), May) :-
+	( Builtin = inline_builtin ->
+		May = no
+	;
+		May = yes
+	).
+code_util__goal_may_allocate_heap_2(unify(_, _, _, Unification, _), May) :-
+	( Unification = construct(_,_,Args,_,_,_,_), Args = [_|_] ->
+		May = yes
+	;
+		May = no
+	).
+	% We cannot safely say that a C code fragment does not allocate memory
+	% without knowing all the #defined macros that expand to incr_hp and
+	% variants thereof.
+code_util__goal_may_allocate_heap_2(pragma_c_code(_, _, _, _, _, _, _), yes).
+code_util__goal_may_allocate_heap_2(some(_Vars, _, Goal), May) :-
+	code_util__goal_may_allocate_heap(Goal, May).
+code_util__goal_may_allocate_heap_2(not(Goal), May) :-
+	code_util__goal_may_allocate_heap(Goal, May).
+code_util__goal_may_allocate_heap_2(conj(Goals), May) :-
+	code_util__goal_list_may_allocate_heap(Goals, May).
+code_util__goal_may_allocate_heap_2(par_conj(_, _), yes).
+code_util__goal_may_allocate_heap_2(disj(Goals, _), May) :-
+	code_util__goal_list_may_allocate_heap(Goals, May).
+code_util__goal_may_allocate_heap_2(switch(_Var, _Det, Cases, _), May) :-
+	code_util__cases_may_allocate_heap(Cases, May).
+code_util__goal_may_allocate_heap_2(if_then_else(_Vars, C, T, E, _), May) :-
+	( code_util__goal_may_allocate_heap(C, yes) ->
+		May = yes
+	; code_util__goal_may_allocate_heap(T, yes) ->
+		May = yes
+	;
+		code_util__goal_may_allocate_heap(E, May)
+	).
+code_util__goal_may_allocate_heap_2(bi_implication(G1, G2), May) :-
+	( code_util__goal_may_allocate_heap(G1, yes) ->
+		May = yes
+	;
+		code_util__goal_may_allocate_heap(G2, May)
+	).
 
-	% This code may _look_ nondeterministic, but it's really semidet,
-	% and Mercury is smart enough to know this.
+:- pred code_util__goal_list_may_allocate_heap(list(hlds_goal)::in, bool::out)
+	is det.
 
-code_util__goal_may_allocate_heap(Goal - _GoalInfo) :-
-	code_util__goal_may_allocate_heap_2(Goal).
+code_util__goal_list_may_allocate_heap([], no).
+code_util__goal_list_may_allocate_heap([Goal | Goals], May) :-
+	( code_util__goal_may_allocate_heap(Goal, yes) ->
+		May = yes
+	;
+		code_util__goal_list_may_allocate_heap(Goals, May)
+	).
+
+:- pred code_util__cases_may_allocate_heap(list(case)::in, bool::out) is det.
 
-:- pred code_util__goal_may_allocate_heap_2(hlds_goal_expr).
-:- mode code_util__goal_may_allocate_heap_2(in) is semidet.
+code_util__cases_may_allocate_heap([], no).
+code_util__cases_may_allocate_heap([case(_, Goal) | Cases], May) :-
+	( code_util__goal_may_allocate_heap(Goal, yes) ->
+		May = yes
+	;
+		code_util__cases_may_allocate_heap(Cases, May)
+	).
 
-code_util__goal_may_allocate_heap_2(generic_call(_, _, _, _)).
-code_util__goal_may_allocate_heap_2(call(_, _, _, Builtin, _, _)) :-
-	Builtin \= inline_builtin.
-code_util__goal_may_allocate_heap_2(
-		unify(_, _, _, construct(_,_,Args,_,_,_,_), _)) :-
-	Args = [_|_].
-code_util__goal_may_allocate_heap_2(some(_Vars, _, Goal)) :-
-	code_util__goal_may_allocate_heap(Goal).
-code_util__goal_may_allocate_heap_2(not(Goal)) :-
-	code_util__goal_may_allocate_heap(Goal).
-code_util__goal_may_allocate_heap_2(conj(Goals)) :-
-	code_util__goal_list_may_allocate_heap(Goals).
-code_util__goal_may_allocate_heap_2(disj(Goals, _)) :-
-	code_util__goal_list_may_allocate_heap(Goals).
-code_util__goal_may_allocate_heap_2(switch(_Var, _Det, Cases, _)) :-
-	code_util__cases_may_allocate_heap(Cases).
-code_util__goal_may_allocate_heap_2(if_then_else(_Vars, A, B, C, _)) :-
-	(
-		code_util__goal_may_allocate_heap(A)
-	;	
-		code_util__goal_may_allocate_heap(B)
-	;
-		code_util__goal_may_allocate_heap(C)
-	).
-
-:- pred code_util__cases_may_allocate_heap(list(case)).
-:- mode code_util__cases_may_allocate_heap(in) is semidet.
-
-code_util__cases_may_allocate_heap([case(_, Goal) | _]) :-
-	code_util__goal_may_allocate_heap(Goal).
-code_util__cases_may_allocate_heap([_ | Cases]) :-
-	code_util__cases_may_allocate_heap(Cases).
-
-code_util__goal_list_may_allocate_heap([Goal | _]) :-
-	code_util__goal_may_allocate_heap(Goal).
-code_util__goal_list_may_allocate_heap([_ | Goals]) :-
-	code_util__goal_list_may_allocate_heap(Goals).
+%-----------------------------------------------------------------------------%
+
+code_util__goal_may_alloc_temp_frame(Goal) :-
+	code_util__goal_may_alloc_temp_frame(Goal, yes).
+
+:- pred code_util__goal_may_alloc_temp_frame(hlds_goal::in, bool::out) is det.
+
+code_util__goal_may_alloc_temp_frame(Goal - _GoalInfo, May) :-
+	code_util__goal_may_alloc_temp_frame_2(Goal, May).
+
+:- pred code_util__goal_may_alloc_temp_frame_2(hlds_goal_expr::in, bool::out)
+	is det.
+
+code_util__goal_may_alloc_temp_frame_2(generic_call(_, _, _, _), no).
+code_util__goal_may_alloc_temp_frame_2(call(_, _, _, _, _, _), no).
+code_util__goal_may_alloc_temp_frame_2(unify(_, _, _, _, _), no).
+	% We cannot safely say that a C code fragment does not allocate
+	% temporary nondet frames without knowing all the #defined macros
+	% that expand to mktempframe and variants thereof. The performance
+	% impact of being too conservative is probably not too bad.
+code_util__goal_may_alloc_temp_frame_2(pragma_c_code(_, _, _, _, _, _, _), yes).
+code_util__goal_may_alloc_temp_frame_2(some(_Vars, _, Goal), May) :-
+	Goal = _ - GoalInfo,
+	goal_info_get_code_model(GoalInfo, CodeModel),
+	( CodeModel = model_non ->
+		May = yes
+	;
+		code_util__goal_may_alloc_temp_frame(Goal, May)
+	).
+code_util__goal_may_alloc_temp_frame_2(not(Goal), May) :-
+	code_util__goal_may_alloc_temp_frame(Goal, May).
+code_util__goal_may_alloc_temp_frame_2(conj(Goals), May) :-
+	code_util__goal_list_may_alloc_temp_frame(Goals, May).
+code_util__goal_may_alloc_temp_frame_2(par_conj(Goals, _), May) :-
+	code_util__goal_list_may_alloc_temp_frame(Goals, May).
+code_util__goal_may_alloc_temp_frame_2(disj(Goals, _), May) :-
+	code_util__goal_list_may_alloc_temp_frame(Goals, May).
+code_util__goal_may_alloc_temp_frame_2(switch(_Var, _Det, Cases, _), May) :-
+	code_util__cases_may_alloc_temp_frame(Cases, May).
+code_util__goal_may_alloc_temp_frame_2(if_then_else(_Vars, C, T, E, _), May) :-
+	( code_util__goal_may_alloc_temp_frame(C, yes) ->
+		May = yes
+	; code_util__goal_may_alloc_temp_frame(T, yes) ->
+		May = yes
+	;
+		code_util__goal_may_alloc_temp_frame(E, May)
+	).
+code_util__goal_may_alloc_temp_frame_2(bi_implication(G1, G2), May) :-
+	( code_util__goal_may_alloc_temp_frame(G1, yes) ->
+		May = yes
+	;
+		code_util__goal_may_alloc_temp_frame(G2, May)
+	).
+
+:- pred code_util__goal_list_may_alloc_temp_frame(list(hlds_goal)::in,
+	bool::out) is det.
+
+code_util__goal_list_may_alloc_temp_frame([], no).
+code_util__goal_list_may_alloc_temp_frame([Goal | Goals], May) :-
+	( code_util__goal_may_alloc_temp_frame(Goal, yes) ->
+		May = yes
+	;
+		code_util__goal_list_may_alloc_temp_frame(Goals, May)
+	).
+
+:- pred code_util__cases_may_alloc_temp_frame(list(case)::in, bool::out)
+	is det.
+
+code_util__cases_may_alloc_temp_frame([], no).
+code_util__cases_may_alloc_temp_frame([case(_, Goal) | Cases], May) :-
+	( code_util__goal_may_alloc_temp_frame(Goal, yes) ->
+		May = yes
+	;
+		code_util__cases_may_alloc_temp_frame(Cases, May)
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/continuation_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/continuation_info.m,v
retrieving revision 1.29
diff -u -b -r1.29 continuation_info.m
--- compiler/continuation_info.m	1999/12/14 04:52:36	1.29
+++ compiler/continuation_info.m	2000/01/15 04:46:14
@@ -65,6 +65,7 @@
 			determinism,	% Determines which stack is used.
 			int,		% Number of stack slots.
 			maybe(int),	% Location of succip on stack.
+			eval_method,	% Of the procedure.
 			maybe(label),	% If the trace level is not none,
 					% this contains the label associated
 					% with the call event, whose stack
@@ -338,7 +339,8 @@
 
 		% Get all the continuation info from the call instructions.
 	global_data_get_proc_layout(GlobalData0, PredProcId, ProcLayoutInfo0),
-	ProcLayoutInfo0 = proc_layout_info(A, B, C, D, E, F, G, H, Internals0),
+	ProcLayoutInfo0 = proc_layout_info(A, B, C, D, E, F, G, H, I,
+		Internals0),
 	GetCallInfo = lambda([Instr::in, Call::out] is semidet, (
 		Instr = call(Target, label(ReturnLabel), LiveInfo, Context, _)
 			- _Comment,
@@ -350,7 +352,8 @@
 	list__foldl(continuation_info__process_continuation(WantReturnInfo),
 		Calls, Internals0, Internals),
 
-	ProcLayoutInfo = proc_layout_info(A, B, C, D, E, F, G, H, Internals),
+	ProcLayoutInfo = proc_layout_info(A, B, C, D, E, F, G, H, I,
+		Internals),
 	global_data_update_proc_layout(GlobalData0, PredProcId, ProcLayoutInfo,
 		GlobalData).
 
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.88
diff -u -b -r1.88 handle_options.m
--- compiler/handle_options.m	2000/01/10 05:26:18	1.88
+++ compiler/handle_options.m	2000/01/15 04:46:16
@@ -338,6 +338,12 @@
 		;
 			[]
 		),
+
+			% The following option allows us to perform retries
+			% from the middle of procedure bodies without requiring
+			% us to store everything on the nondet stack that may
+			% be hijacked being saved on entry to every procedure.
+		globals__io_set_option(allow_hijacks, bool(no)),
 			% The following option prevents useless variables
 			% from cluttering the trace. Its explicit setting
 			% removes a source of variability in the goal paths
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.67
diff -u -b -r1.67 hlds_goal.m
--- compiler/hlds_goal.m	2000/01/13 06:15:38	1.67
+++ compiler/hlds_goal.m	2000/01/15 04:46:16
@@ -572,7 +572,13 @@
 				% a constraint.  See constraint.m
 				% for the definition of this.
 	    ;	(impure)	% This goal is impure.  See hlds_pred.m.
-	    ;	(semipure).	% This goal is semipure.  See hlds_pred.m.
+	;	(semipure)	% This goal is semipure.  See hlds_pred.m.
+	;	call_table_gen.	% This goal generates the variable that
+				% represents the call table. If debugging is
+				% enabled, the code generator needs to save
+				% the value of this variable in its stack slot
+				% as soon as it is generated; this marker
+				% tells the code generator when this happens.
 
 	% see compiler/notes/allocation.html for what these alternatives mean
 :- type resume_point	--->	resume_point(set(prog_var), resume_locs)
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.235
diff -u -b -r1.235 hlds_out.m
--- compiler/hlds_out.m	2000/01/13 06:15:45	1.235
+++ compiler/hlds_out.m	2000/01/15 04:46:17
@@ -2840,6 +2840,7 @@
 	{ proc_info_typeinfo_varmap(Proc, TypeInfoMap) },
 	{ proc_info_typeclass_info_varmap(Proc, TypeClassInfoMap) },
 	{ proc_info_is_address_taken(Proc, IsAddressTaken) },
+	{ proc_info_get_call_table_tip(Proc, MaybeCallTableTip) },
 	{ Indent1 is Indent + 1 },
 
 	hlds_out__write_indent(Indent1),
@@ -2879,6 +2880,14 @@
 		io__write_string("% address is taken\n")
 	;
 		io__write_string("% address is not taken\n")
+	),
+
+	( { MaybeCallTableTip = yes(CallTableTip) } ->
+		io__write_string("% call table tip: "),
+		mercury_output_var(CallTableTip, VarSet, AppendVarnums),
+		io__write_string("\n")
+	;
+		[]
 	),
 
 	hlds_out__write_indent(Indent),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.69
diff -u -b -r1.69 hlds_pred.m
--- compiler/hlds_pred.m	2000/01/13 06:15:52	1.69
+++ compiler/hlds_pred.m	2000/01/15 04:46:17
@@ -1488,6 +1488,18 @@
 :- pred proc_info_set_rl_exprn_id(proc_info, rl_exprn_id, proc_info).
 :- mode proc_info_set_rl_exprn_id(in, in, out) is det.
 
+:- pred proc_info_get_maxfr_slot_flag(proc_info, bool).
+:- mode proc_info_get_maxfr_slot_flag(in, out) is det.
+
+:- pred proc_info_set_maxfr_slot_flag(proc_info, bool, proc_info).
+:- mode proc_info_set_maxfr_slot_flag(in, in, out) is det.
+
+:- pred proc_info_get_call_table_tip(proc_info, maybe(prog_var)).
+:- mode proc_info_get_call_table_tip(in, out) is det.
+
+:- pred proc_info_set_call_table_tip(proc_info, maybe(prog_var), proc_info).
+:- mode proc_info_set_call_table_tip(in, in, out) is det.
+
 	% For a set of variables V, find all the type variables in the types 
 	% of the variables in V, and return set of typeinfo variables for 
 	% those type variables. (find all typeinfos for variables in V).
@@ -1595,13 +1607,34 @@
 					% must be considered as having its
 					% address taken, since it is possible
 					% that some other module may do so.
-			maybe(rl_exprn_id)
+			maybe(rl_exprn_id),
 					% For predicates with an
 					% `aditi_top_down' marker, which are
 					% executed top-down on the Aditi side
 					% of the connection, we generate an RL
 					% expression, for which this is an
 					% identifier. See rl_update.m.
+			bool,		% True iff tracing is enabled, this
+					% is a procedure that lives on the det
+					% stack, and the code of this procedure
+					% may create a frame on the det stack.
+					% (Only in these circumstances do we
+					% need to reserve a stack slot to hold
+					% the value of maxfr at the call, for
+					% use in implementing retry.)
+					%
+					% This slot is set during the live_vars
+					% pass; it is invalid before then.
+			maybe(prog_var)	% If the tracing is enabled and the
+					% procedure's evaluation method is
+					% memo, loopcheck or minimal, this
+					% slot identifies the variable that
+					% holds the tip of the call table;
+					% when this variable is bound, we
+					% must put this variable in its stack
+					% slot, for use by the retry command.
+					% Otherwise, this field will be set to
+					% `no'.
 		).
 
 	% Some parts of the procedure aren't known yet. We initialize
@@ -1631,7 +1664,7 @@
 		MaybeDet, BodyVarSet, BodyTypes, HeadVars, Modes, MaybeArgLives,
 		ClauseBody, MContext, StackSlots, InferredDet, CanProcess,
 		ArgInfo, InitialLiveness, TVarsMap, TCVarsMap, eval_normal,
-		no, no, DeclaredModes, IsAddressTaken, RLExprn
+		no, no, DeclaredModes, IsAddressTaken, RLExprn, no, no
 	).
 
 proc_info_set(DeclaredDetism, BodyVarSet, BodyTypes, HeadVars, HeadModes,
@@ -1643,7 +1676,7 @@
 		DeclaredDetism, BodyVarSet, BodyTypes, HeadVars, HeadModes,
 		HeadLives, Goal, Context, StackSlots, InferredDetism,
 		CanProcess, ArgInfo, Liveness, TVarMap, TCVarsMap, eval_normal, 
-		ArgSizes, Termination, no, IsAddressTaken, RLExprn).
+		ArgSizes, Termination, no, IsAddressTaken, RLExprn, no, no).
 
 proc_info_create(VarSet, VarTypes, HeadVars, HeadModes, Detism, Goal,
 		Context, TVarMap, TCVarsMap, IsAddressTaken, ProcInfo) :-
@@ -1654,14 +1687,15 @@
 	ProcInfo = procedure(yes(Detism), VarSet, VarTypes, HeadVars, HeadModes,
 		MaybeHeadLives, Goal, Context, StackSlots, Detism, yes, [],
 		Liveness, TVarMap, TCVarsMap, eval_normal, no, no, no, 
-		IsAddressTaken, RLExprn).
+		IsAddressTaken, RLExprn, no, no).
 
 proc_info_set_body(ProcInfo0, VarSet, VarTypes, HeadVars, Goal,
 		TI_VarMap, TCI_VarMap, ProcInfo) :-
 	ProcInfo0 = procedure(A, _, _, _, E, F, _,
-		H, I, J, K, L, M, _, _, P, Q, R, S, T, U),
+		H, I, J, K, L, M, _, _, P, Q, R, S, T, U, V, W),
 	ProcInfo = procedure(A, VarSet, VarTypes, HeadVars, E, F, Goal,
-		H, I, J, K, L, M, TI_VarMap, TCI_VarMap, P, Q, R, S, T, U).
+		H, I, J, K, L, M, TI_VarMap, TCI_VarMap,
+		P, Q, R, S, T, U, V, W).
 
 proc_info_interface_determinism(ProcInfo, Determinism) :-
 	proc_info_declared_determinism(ProcInfo, MaybeDeterminism),
@@ -1719,88 +1753,96 @@
 
 proc_info_declared_determinism(ProcInfo, A) :-
 	ProcInfo = procedure(A, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-    		_, _, _, _, _).
+    		_, _, _, _, _, _, _).
 
 proc_info_varset(ProcInfo, B) :-
 	ProcInfo = procedure(_, B, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_vartypes(ProcInfo, C) :-
 	ProcInfo = procedure(_, _, C, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_headvars(ProcInfo, D) :-
 	ProcInfo = procedure(_, _, _, D, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_argmodes(ProcInfo, E) :-
 	ProcInfo = procedure(_, _, _, _, E, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_maybe_arglives(ProcInfo, F) :-
 	ProcInfo = procedure(_, _, _, _, _, F, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_goal(ProcInfo, G) :-
 	ProcInfo = procedure(_, _, _, _, _, _, G, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_context(ProcInfo, H) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, H, _, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_stack_slots(ProcInfo, I) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, I, _, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_inferred_determinism(ProcInfo, J) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, J, _, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_can_process(ProcInfo, K) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, K, _, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_arg_info(ProcInfo, L) :- 
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, L, _, _, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_liveness_info(ProcInfo, M) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, M, _, _, _,
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_typeinfo_varmap(ProcInfo, N) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, N, _, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_typeclass_info_varmap(ProcInfo, O) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, O, _, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_eval_method(ProcInfo, P) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, P, 
-		_, _, _, _, _).
+		_, _, _, _, _, _, _).
 
 proc_info_get_maybe_arg_size_info(ProcInfo, Q) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		Q, _, _, _, _).
+		Q, _, _, _, _, _, _).
 
 proc_info_get_maybe_termination_info(ProcInfo, R) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, R, _, _, _).
+		_, R, _, _, _, _, _).
 
 proc_info_maybe_declared_argmodes(ProcInfo, S) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, S, _, _).
+		_, _, S, _, _, _, _).
 
 proc_info_is_address_taken(ProcInfo, T) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, T, _).
+		_, _, _, T, _, _, _).
 
 proc_info_get_rl_exprn_id(ProcInfo, U) :-
+	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
+		_, _, _, _, U, _, _).
+
+proc_info_get_maxfr_slot_flag(ProcInfo, V) :-
 	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
-		_, _, _, _, U).
+		_, _, _, _, _, V, _).
 
+proc_info_get_call_table_tip(ProcInfo, W) :-
+	ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 
+		_, _, _, _, _, _, W).
+
 % :- type proc_info
 % 	--->	procedure(
 % A			maybe(determinism),
@@ -1852,122 +1894,155 @@
 % 					% analysis.
 % S			maybe(list(mode)),
 % 					% declared modes of arguments.
-% T			is_address_taken
+% T			is_address_taken,
 %					% Is the address of this procedure
 %					% taken? If yes, we will need to use
 %					% typeinfo liveness for them, so that
 %					% deep_copy and accurate gc have the
 %					% RTTI they need for copying closures.
-% U			maybe(rl_exprn_id)
+% U			maybe(rl_exprn_id),
 %					% For predicates with an
 %					% `aditi_top_down' marker, which are
 %					% executed top-down on the Aditi side
 %					% of the connection, we generate an RL
 %					% expression, for which this is an
 %					% identifier. See rl_update.m.
+% V			bool,		% True iff trace level is deep, this
+%					% is a procedure that lives on the det
+%					% stack, and the code of this procedure
+%					% may create a frame on the det stack.
+%					% (Only in these circumstances do we
+%					% need to reserve a stack slot to hold
+%					% the value of maxfr at the call, for
+%					% use in implementing retry.)
+%					%
+%					% This slot is set during the live_vars
+%					% pass; it is invalid before then.
+% W			maybe(var)	% If the tracing is enabled and the
+%					% procedure's evaluation method is
+%					% memo, loopcheck or minimal, this
+%					% slot identifies the variable that
+%					% holds the tip of the call table;
+%					% when this variable is bound, we
+%					% must put this variable in its stack
+%					% slot, for use by the retry command.
+%					% Otherwise, this field will be set to
+%					% `no'.
 %		).
 
 proc_info_set_varset(ProcInfo0, B, ProcInfo) :-
 	ProcInfo0 = procedure(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_vartypes(ProcInfo0, C, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, _, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_headvars(ProcInfo0, D, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, _, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_argmodes(ProcInfo0, E, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, _, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_maybe_arglives(ProcInfo0, F, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_goal(ProcInfo0, G, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_stack_slots(ProcInfo0, I, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, _, J, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_inferred_determinism(ProcInfo0, J, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_can_process(ProcInfo0, K, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, _, L, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_arg_info(ProcInfo0, L, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_liveness_info(ProcInfo0, M, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_typeinfo_varmap(ProcInfo0, N, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_typeclass_info_varmap(ProcInfo0, O, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, _, 
-		P, Q, R, S, T, U),
+		P, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_eval_method(ProcInfo0, P, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
-		_, Q, R, S, T, U),
+		_, Q, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_maybe_arg_size_info(ProcInfo0, Q, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, _, R, S, T, U),
+		P, _, R, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_maybe_termination_info(ProcInfo0, R, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, _, S, T, U),
+		P, Q, _, S, T, U, V, W),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, U).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_set_rl_exprn_id(ProcInfo0, U, ProcInfo) :-
+	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
+		P, Q, R, S, T, _, V, W),
+	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
+		P, Q, R, S, T, yes(U), V, W).
+
+proc_info_set_maxfr_slot_flag(ProcInfo0, V, ProcInfo) :-
+	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
+		P, Q, R, S, T, U, _, W),
+	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
+		P, Q, R, S, T, U, V, W).
+
+proc_info_set_call_table_tip(ProcInfo0, W, ProcInfo) :-
 	ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, _),
+		P, Q, R, S, T, U, V, _),
 	ProcInfo  = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 
-		P, Q, R, S, T, yes(U)).
+		P, Q, R, S, T, U, V, W).
 
 proc_info_get_typeinfo_vars_setwise(ProcInfo, Vars, TypeInfoVars) :-
 	set__to_sorted_list(Vars, VarList),
Index: compiler/live_vars.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/live_vars.m,v
retrieving revision 1.85
diff -u -b -r1.85 live_vars.m
--- compiler/live_vars.m	1999/10/25 03:49:06	1.85
+++ compiler/live_vars.m	2000/01/15 04:46:18
@@ -57,17 +57,25 @@
 		set__init(ResumeVars0),
 		LiveSets1 = LiveSets0
 	),
-	trace__reserved_slots(ProcInfo0, Globals, NumReservedSlots),
+	trace__do_we_need_maxfr_slot(Globals, ProcInfo0, ProcInfo1),
+	trace__reserved_slots(ProcInfo1, Globals, NumReservedSlots,
+		MaybeReservedVarInfo),
+	( MaybeReservedVarInfo = yes(ResVar - _) ->
+		set__singleton_set(ResVarSet, ResVar),
+		set__insert(LiveSets1, ResVarSet, LiveSets2)
+	;
+		LiveSets2 = LiveSets1
+	),
 	body_should_use_typeinfo_liveness(Globals, TypeInfoLiveness),
-	build_live_sets_in_goal(Goal0, Liveness0, ResumeVars0, LiveSets1,
-		ModuleInfo, ProcInfo0, TypeInfoLiveness,
+	build_live_sets_in_goal(Goal0, Liveness0, ResumeVars0, LiveSets2,
+		ModuleInfo, ProcInfo1, TypeInfoLiveness,
 		_Liveness, _ResumeVars, LiveSets),
 	graph_colour__group_elements(LiveSets, ColourSets),
 	set__to_sorted_list(ColourSets, ColourList),
 	allocate_stack_slots(ColourList, CodeModel, NumReservedSlots,
-		StackSlots),
+		MaybeReservedVarInfo, StackSlots),
 
-	proc_info_set_stack_slots(ProcInfo0, StackSlots, ProcInfo).
+	proc_info_set_stack_slots(ProcInfo1, StackSlots, ProcInfo).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -576,35 +584,44 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred allocate_stack_slots(list(set(prog_var)), code_model, int, stack_slots).
-:- mode allocate_stack_slots(in, in, in, out) is det.
+:- pred allocate_stack_slots(list(set(prog_var)), code_model, int,
+	maybe(pair(prog_var, int)), stack_slots).
+:- mode allocate_stack_slots(in, in, in, in, out) is det.
 
-allocate_stack_slots(ColourList, CodeModel, NumReservedSlots, StackSlots) :-
+allocate_stack_slots(ColourList, CodeModel, NumReservedSlots,
+		MaybeReservedVarInfo, StackSlots) :-
 	map__init(StackSlots0),
 		% The reserved slots are referred to by fixed number
 		% (e.g. framevar(1)) in trace__setup.
 	FirstVarSlot is 1 + NumReservedSlots,
-	allocate_stack_slots_2(ColourList, FirstVarSlot, CodeModel,
-		StackSlots0, StackSlots).
+	allocate_stack_slots_2(ColourList, CodeModel, FirstVarSlot,
+		MaybeReservedVarInfo, StackSlots0, StackSlots).
 
-:- pred allocate_stack_slots_2(list(set(prog_var)), int, code_model,
-	stack_slots, stack_slots).
-:- mode allocate_stack_slots_2(in, in, in, in, out) is det.
+:- pred allocate_stack_slots_2(list(set(prog_var)), code_model,int,
+	maybe(pair(prog_var, int)), stack_slots, stack_slots).
+:- mode allocate_stack_slots_2(in, in, in, in, in, out) is det.
 
-allocate_stack_slots_2([], _N, _CodeModel, StackSlots, StackSlots).
-allocate_stack_slots_2([Vars | VarSets], N0, CodeModel,
+allocate_stack_slots_2([], _, _, _, StackSlots, StackSlots).
+allocate_stack_slots_2([Vars | VarSets], CodeModel, N0, MaybeReservedVarInfo,
 		StackSlots0, StackSlots) :-
-	set__to_sorted_list(Vars, VarList),
 	(
-		CodeModel = model_non
+		MaybeReservedVarInfo = yes(ResVar - ResSlotNum),
+		set__member(ResVar, Vars)
 	->
-		Slot = framevar(N0)
+		SlotNum = ResSlotNum,
+		N1 = N0
 	;
-		Slot = stackvar(N0)
+		SlotNum = N0,
+		N1 = N0 + 1
 	),
+	( CodeModel = model_non ->
+		Slot = framevar(SlotNum)
+	;
+		Slot = stackvar(SlotNum)
+	),
+	set__to_sorted_list(Vars, VarList),
 	allocate_same_stack_slot(VarList, Slot, StackSlots0, StackSlots1),
-	N1 is N0 + 1,
-	allocate_stack_slots_2(VarSets, N1, CodeModel,
+	allocate_stack_slots_2(VarSets, CodeModel, N1, MaybeReservedVarInfo,
 		StackSlots1, StackSlots).
 
 :- pred allocate_same_stack_slot(list(prog_var), lval, stack_slots,
Index: compiler/optimize.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/optimize.m,v
retrieving revision 1.21
diff -u -b -r1.21 optimize.m
--- compiler/optimize.m	1999/12/14 04:52:51	1.21
+++ compiler/optimize.m	2000/01/15 04:46:21
@@ -51,7 +51,7 @@
 		global_data_maybe_get_proc_layout(GlobalData, PredProcId,
 			ProcLayout)
 	->
-		ProcLayout = proc_layout_info(_, _, _, _, _, _, _, _,
+		ProcLayout = proc_layout_info(_, _, _, _, _, _, _, _, _,
 			LabelMap),
 		map__sorted_keys(LabelMap, LayoutLabels),
 		set__sorted_list_to_set(LayoutLabels, LayoutLabelSet)
Index: compiler/stack_layout.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/stack_layout.m,v
retrieving revision 1.43
diff -u -b -r1.43 stack_layout.m
--- compiler/stack_layout.m	2000/01/14 01:10:43	1.43
+++ compiler/stack_layout.m	2000/01/15 04:46:23
@@ -21,7 +21,7 @@
 %
 %---------------------------------------------------------------------------%
 %
-% Data Stucture: stack_layouts
+% Data Stucture: procedure ayouts
 %
 % If the option basic_stack_layout is set, we generate a MR_Stack_Layout_Entry
 % for each procedure. This will be stored in the global variable whose name is
@@ -68,44 +68,76 @@
 % If the option trace_stack_layout is set, i.e. if we are doing execution
 % tracing, the structure will also include some extra fields:
 %
-%	call trace info		(MR_Stack_Layout_Label *) - points to the
-%				layout structure of the call event
-%	module layout		(MR_Module_Layout *) - points to the layout
-%				struct of the containing module.
-%	max reg at trace event	(int_least16_t) - the number of the highest
-%				numbered rN register live at a trace event
-%				inside the procedure
-%	maybe from full		(int_least8_t) - number of the stack slot of
-%				the from_full flag, if the procedure is
-%				shallow traced
-%	maybe trail		(int_least8_t) - number of the first of two
-%				stack slots used for recording the state of
-%				the trail, if trailing is enabled
-%	maybe decl debug	(int_least8_t) - number of the first of two
-%				stack slots used by the declarative debugger,
-%				if --trace-decl is set
-%
-% The first will point to the per-label layout info for the label associated
-% with the call event at the entry to the procedure. The purpose of this
-% information is to allow the runtime debugger to find out which variables
+%	struct MR_Stack_Layout_Label_Struct	*MR_sle_call_label;
+%	struct MR_Module_Layout_Struct		*MR_sle_module_layout;
+%	MR_int_least16_t			MR_sle_max_r_num;
+%	MR_int_least8_t				MR_sle_maybe_from_full;
+%	MR_int_least8_t				MR_sle_maybe_trail;
+%	MR_int_least8_t				MR_sle_maybe_maxfr;
+%	MR_int_least8_t				MR_sle_eval_method;
+%	MR_int_least8_t				MR_sle_maybe_call_table;
+%	MR_int_least8_t				MR_sle_maybe_decl_debug;
+%
+% The call_label field points to the label layout structure for the label
+% associated with the call event at the entry to the procedure. The purpose
+% of this field is to allow the runtime debugger to find out which variables
 % are where on entry, so it can reexecute the procedure if asked to do so
 % and if the values of the required variables are still available.
 % (If trace_stack_layout is not set, this field will be present,
 % but it will be set to NULL.)
 %
-% If the procedure is compiled with deep tracing, the fourth field will contain
-% a negative number. If it is compiled with shallow tracing, it will contain
-% the number of the stack slot that holds the flag that says whether this
-% incarnation of the procedure was called from deeply traced code or not.
-% (The determinism of the procedure decides whether the stack slot refers
-% to a stackvar or a framevar.)
-%
-% If --trace-decl is not set, the sixth field will contain a negative number.
-% If it is set, it will contain the number of the first of two stack slots
-% used by the declarative debugger; the other slot is the next higher numbered
-% one. (The determinism of the procedure decides whether the stack slot refers
-% to a stackvar or a framevar.)
+% The module layout field points to the module info structure of the module
+% containing the procedure. This allows the debugger access to the string table
+% stored there, as well the table associating source-file contexts with labels.
+%
+% The max_r_num field tells the debugger which Mercury abstract machine
+% registers need saving in MR_trace: besides the special registers, it is
+% the general-purpose registers rN for values of N up to and including the
+% value of this field. Note that this field contains an upper bound; in
+% general, there will be calls to MR_trace at which the number of the highest
+% numbered gp registers is less than this. However, storing the upper bound
+% gets us almost all the benefit (of not saving/restoring all the thousand gp
+% abstract machine registers) for a small fraction of the static space cost
+% of storing the actual number in label layout structures.
+%
+% If the procedure is compiled with deep tracing, the maybe from full field
+% will contain a negative number. If it is compiled with shallow tracing,
+% it will contain the number of the stack slot that holds the flag that says
+% whether this incarnation of the procedure was called from deeply traced code
+% or not. (The determinism of the procedure decides whether the stack slot
+% refers to a stackvar or a framevar.)
+%
+% If trailing is not enabled, the maybe trail field will contain a negative
+% number. If it is enabled, it will contain number of the first of two stack
+% slots used for recording the state of the trail on entry to the procedure.
+% The first contains the trail pointer, the second the ticket.
+%
+% If the procedure lives on the nondet stack, or if it cannot create any
+% temporary nondet stack frames, the maybe maxfr field will contain a negative
+% number. If it lives on the det stack, and can create temporary nondet stack
+% frames, it will contain the number number of the stack slot that contains the
+% value of maxfr on entry, for use in executing the retry debugger command
+% from the middle of the procedure.
+%
+% The eval method field contains a representation of the evaluation method
+% used by the procedure. The retry command needs this information if it is
+% to reset the call tables of the procedure invocations being retried. Note
+% that this field is intended to be cast to the type MR_EvalMethod before use;
+% the reason why it is declared as MR_int_least8_t in the C definition of the
+% procedure layout structure is that at the moment we have no other way of
+% guaranteeing that the structures generated by the code in this file match
+% the expectations of the C compiler.
+%
+% If --trace-decl is not set, the maybe decl field will contain a negative
+% number. If it is set, it will contain the number of the first of two stack
+% slots used by the declarative debugger; the other slot is the next higher
+% numbered one. (The determinism of the procedure decides whether the stack
+% slot refers to a stackvar or a framevar.)
 %
+%---------------------------------------------------------------------------%
+%
+% Data Stucture: label ayouts
+%
 % If the option basic_stack_layout is set, we generate stack layout tables
 % for some labels internal to the procedure. This table will be stored in the
 % global variable whose name is
@@ -519,11 +551,11 @@
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__construct_layouts(ProcLayoutInfo) -->
-	{ ProcLayoutInfo = proc_layout_info(EntryLabel, Detism,
-		StackSlots, SuccipLoc, MaybeCallLabel, MaxTraceReg,
+	{ ProcLayoutInfo = proc_layout_info(EntryLabel, Detism, StackSlots,
+		SuccipLoc, EvalMethod, MaybeCallLabel, MaxTraceReg,
 		TraceSlotInfo, ForceProcIdLayout, InternalMap) },
-	stack_layout__construct_proc_layout(EntryLabel, Detism,
-		StackSlots, SuccipLoc, MaybeCallLabel, MaxTraceReg,
+	stack_layout__construct_proc_layout(EntryLabel, Detism, StackSlots,
+		SuccipLoc, EvalMethod, MaybeCallLabel, MaxTraceReg,
 		TraceSlotInfo, ForceProcIdLayout),
 	{ map__to_assoc_list(InternalMap, Internals) },
 	list__foldl(stack_layout__construct_internal_layout(EntryLabel),
@@ -621,13 +653,13 @@
 	% Construct a procedure-specific layout.
 
 :- pred stack_layout__construct_proc_layout(label::in, determinism::in,
-	int::in, maybe(int)::in, maybe(label)::in, int::in,
-	trace_slot_info::in, bool::in,
+	int::in, maybe(int)::in, eval_method::in, maybe(label)::in,
+	int::in, trace_slot_info::in, bool::in,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
 stack_layout__construct_proc_layout(EntryLabel, Detism, StackSlots,
-		MaybeSuccipLoc, MaybeCallLabel, MaxTraceReg, TraceSlotInfo,
-		ForceProcIdLayout) -->
+		MaybeSuccipLoc, EvalMethod, MaybeCallLabel, MaxTraceReg,
+		TraceSlotInfo, ForceProcIdLayout) -->
 	{
 		MaybeSuccipLoc = yes(Location0)
 	->
@@ -691,8 +723,9 @@
 			ProcLabel) },
 		{ stack_layout__construct_procid_rvals(ProcLabel, IdRvals,
 			IdArgTypes) },
-		stack_layout__construct_trace_layout(MaybeCallLabel,
-			MaxTraceReg, TraceSlotInfo, TraceRvals, TraceArgTypes),
+		stack_layout__construct_trace_layout(EvalMethod,
+			MaybeCallLabel, MaxTraceReg, TraceSlotInfo,
+			TraceRvals, TraceArgTypes),
 		{ list__append(IdRvals, TraceRvals, IdTraceRvals) },
 		{ IdTraceArgTypes = initial(IdArgTypes, TraceArgTypes) }
 	;
@@ -714,11 +747,12 @@
 		Rvals, ArgTypes, []) },
 	stack_layout__add_proc_layout_data(CData, CDataName, EntryLabel).
 
-:- pred stack_layout__construct_trace_layout(maybe(label)::in, int::in,
-	trace_slot_info::in, list(maybe(rval))::out, create_arg_types::out,
+:- pred stack_layout__construct_trace_layout(eval_method::in,
+	maybe(label)::in, int::in, trace_slot_info::in,
+	list(maybe(rval))::out, create_arg_types::out,
 	stack_layout_info::in, stack_layout_info::out) is det.
 
-stack_layout__construct_trace_layout(MaybeCallLabel, MaxTraceReg,
+stack_layout__construct_trace_layout(EvalMethod, MaybeCallLabel, MaxTraceReg,
 		TraceSlotInfo, Rvals, ArgTypes) -->
 	stack_layout__get_module_name(ModuleName),
 	stack_layout__get_trace_stack_layout(TraceLayout),
@@ -736,28 +770,42 @@
 				data_addr(ModuleName, module_layout)))),
 		MaxTraceRegRval = yes(const(int_const(MaxTraceReg))),
 		TraceSlotInfo = trace_slot_info(MaybeFromFullSlot,
-			MaybeDeclSlots, MaybeTrailSlot),
+			MaybeDeclSlots, MaybeTrailSlots, MaybeMaxfrSlot,
+			MaybeCallTableSlot),
+		stack_layout__represent_eval_method(EvalMethod, EvalMethodInt),
+		EvalMethodRval = yes(const(int_const(EvalMethodInt))),
 		( MaybeFromFullSlot = yes(FromFullSlot) ->
 			FromFullRval = yes(const(int_const(FromFullSlot)))
 		;
 			FromFullRval = yes(const(int_const(-1)))
 		),
+		( MaybeTrailSlots = yes(FirstTrailSlot) ->
+			TrailRval = yes(const(int_const(FirstTrailSlot)))
+		;
+			TrailRval = yes(const(int_const(-1)))
+		),
+		( MaybeMaxfrSlot = yes(MaxfrSlot) ->
+			MaxfrRval = yes(const(int_const(MaxfrSlot)))
+		;
+			MaxfrRval = yes(const(int_const(-1)))
+		),
+		( MaybeCallTableSlot = yes(CallTableSlot) ->
+			CallTableRval = yes(const(int_const(CallTableSlot)))
+		;
+			CallTableRval = yes(const(int_const(-1)))
+		),
 		( MaybeDeclSlots = yes(DeclSlot) ->
 			DeclRval = yes(const(int_const(DeclSlot)))
 		;
 			DeclRval = yes(const(int_const(-1)))
 		),
-		( MaybeTrailSlot = yes(TrailSlot) ->
-			TrailRval = yes(const(int_const(TrailSlot)))
-		;
-			TrailRval = yes(const(int_const(-1)))
-		),
-		Rvals = [CallRval, ModuleRval,
-			MaxTraceRegRval, FromFullRval, TrailRval, DeclRval],
+		Rvals = [CallRval, ModuleRval, MaxTraceRegRval,
+			FromFullRval, TrailRval, MaxfrRval,
+			EvalMethodRval, CallTableRval, DeclRval],
 		ArgTypes = initial([
 			2 - yes(data_ptr),
 			1 - yes(int_least16),
-			3 - yes(int_least8)],
+			6 - yes(int_least8)],
 			none)
 	;
 		% Indicate the absence of the trace layout fields.
@@ -765,6 +813,13 @@
 		ArgTypes = initial([1 - yes(integer)], none)
 	}.
 
+:- pred stack_layout__represent_eval_method(eval_method::in, int::out) is det.
+
+stack_layout__represent_eval_method(eval_normal,     0).
+stack_layout__represent_eval_method(eval_loop_check, 1).
+stack_layout__represent_eval_method(eval_memo,       2).
+stack_layout__represent_eval_method(eval_minimal,    3).
+
 %---------------------------------------------------------------------------%
 
 :- pred stack_layout__construct_procid_rvals(proc_label::in,
@@ -786,7 +841,8 @@
 				yes(const(int_const(Arity))),
 				yes(const(int_const(Mode)))
 			],
-		ArgTypes = [4 - no, 2 - yes(int_least16)]
+		ArgTypes = [1 - yes(integer), 3 - yes(string),
+				2 - yes(int_least16)]
 	;
 		ProcLabel = special_proc(DefModule, PredName, TypeModule,
 			TypeName, Arity, ProcId),
@@ -801,7 +857,7 @@
 				yes(const(int_const(Arity))),
 				yes(const(int_const(Mode)))
 			],
-		ArgTypes = [4 - no, 2 - yes(int_least16)]
+		ArgTypes = [4 - yes(string), 2 - yes(int_least16)]
 	).
 
 :- pred stack_layout__represent_pred_or_func(pred_or_func::in, int::out) is det.
Index: compiler/table_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/table_gen.m,v
retrieving revision 1.14
diff -u -b -r1.14 table_gen.m
--- compiler/table_gen.m	1999/12/21 01:22:59	1.14
+++ compiler/table_gen.m	2000/01/15 04:46:27
@@ -1,5 +1,5 @@
 %-----------------------------------------------------------------------------%
-% Copyright (C) 1997-1999 The University of Melbourne.
+% Copyright (C) 1997-2000 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.
 %-----------------------------------------------------------------------------%
@@ -252,19 +252,22 @@
 		table_gen__create_new_det_goal(EvalMethod, OrigGoal,
 			PredId, ProcId, HeadVars, ArgModes,
 			VarTypes0, VarTypes, VarSet0, VarSet,
-			TableInfo0, TableInfo, Goal)
+			TableInfo0, TableInfo, CallTableTip, Goal),
+		MaybeCallTableTip = yes(CallTableTip)
 	;
 		CodeModel = model_semi,
 		table_gen__create_new_semi_goal(EvalMethod, OrigGoal,
 			PredId, ProcId, HeadVars, ArgModes,
 			VarTypes0, VarTypes, VarSet0, VarSet,
-			TableInfo0, TableInfo, Goal)
+			TableInfo0, TableInfo, CallTableTip, Goal),
+		MaybeCallTableTip = yes(CallTableTip)
 	;
 		CodeModel = model_non,
 		table_gen__create_new_non_goal(EvalMethod, OrigGoal,
 			PredId, ProcId, HeadVars, ArgModes,
 			VarTypes0, VarTypes, VarSet0, VarSet,
-			TableInfo0, TableInfo, Goal)
+			TableInfo0, TableInfo, CallTableTip, Goal),
+		MaybeCallTableTip = yes(CallTableTip)
 	),
 
 	table_info_extract(TableInfo, Module1, PredInfo1, ProcInfo1),
@@ -273,7 +276,8 @@
 	% and save in the module info
 	proc_info_set_goal(ProcInfo1, Goal, ProcInfo2),
 	proc_info_set_varset(ProcInfo2, VarSet, ProcInfo3),
-	proc_info_set_vartypes(ProcInfo3, VarTypes, ProcInfo),
+	proc_info_set_vartypes(ProcInfo3, VarTypes, ProcInfo4),
+	proc_info_set_call_table_tip(ProcInfo4, MaybeCallTableTip, ProcInfo),
 
 	pred_info_procedures(PredInfo1, ProcTable1),
 	map__det_update(ProcTable1, ProcId, ProcInfo, ProcTable),
@@ -291,11 +295,11 @@
 	pred_id::in, proc_id::in, list(prog_var)::in, list(mode)::in,
 	map(prog_var, type)::in, map(prog_var, type)::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
-	hlds_goal::out) is det.
+	prog_var::out, hlds_goal::out) is det.
 
 table_gen__create_new_det_goal(EvalMethod, OrigGoal, PredId, ProcId,
 		HeadVars, HeadVarModes, VarTypes0, VarTypes,
-		VarSet0, VarSet, TableInfo0, TableInfo, Goal) :-
+		VarSet0, VarSet, TableInfo0, TableInfo, TableVar, Goal) :-
 	OrigGoal = _ - OrigGoalInfo,
 	goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
@@ -306,7 +310,7 @@
 	get_input_output_vars(HeadVars, HeadVarModes, Module, InputVars,
 		OutputVars),
 
-	generate_det_lookup_goal(InputVars, PredId, ProcId, Context,
+	generate_simple_lookup_goal(InputVars, PredId, ProcId, Context,
 		VarTypes0, VarTypes1, VarSet0, VarSet1, TableInfo0, TableInfo1,
 		TableVar, LookUpGoal),
 	generate_call("table_simple_is_complete", [TableVar], semidet,
@@ -382,11 +386,11 @@
 	pred_id::in, proc_id::in, list(prog_var)::in, list(mode)::in,
 	map(prog_var, type)::in, map(prog_var, type)::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
-	hlds_goal::out) is det.
+	prog_var::out, hlds_goal::out) is det.
 
 table_gen__create_new_semi_goal(EvalMethod, OrigGoal, PredId, ProcId,
 		HeadVars, HeadVarModes, VarTypes0, VarTypes,
-		VarSet0, VarSet, TableInfo0, TableInfo, Goal) :-
+		VarSet0, VarSet, TableInfo0, TableInfo, TableVar, Goal) :-
 	OrigGoal = _ - OrigGoalInfo,
 	goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
@@ -396,7 +400,7 @@
 	get_input_output_vars(HeadVars, HeadVarModes, Module, InputVars,
 		OutputVars),
 
-	generate_det_lookup_goal(InputVars, PredId, ProcId, Context,
+	generate_simple_lookup_goal(InputVars, PredId, ProcId, Context,
 		VarTypes0, VarTypes1, VarSet0, VarSet1, TableInfo0, TableInfo1,
 		TableVar, LookUpGoal),
 	generate_call("table_simple_is_complete", [TableVar],
@@ -528,11 +532,11 @@
 	pred_id::in, proc_id::in, list(prog_var)::in, list(mode)::in,
 	map(prog_var, type)::in, map(prog_var, type)::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
-	hlds_goal::out) is det.
+	prog_var::out, hlds_goal::out) is det.
 
 table_gen__create_new_non_goal(EvalMethod, OrigGoal, PredId, ProcId,
 		HeadVars, HeadVarModes, VarTypes0, VarTypes,
-		VarSet0, VarSet, TableInfo0, TableInfo, Goal) :-
+		VarSet0, VarSet, TableInfo0, TableInfo, TableVar, Goal) :-
 	OrigGoal = _ - OrigGoalInfo,
 	goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
@@ -645,12 +649,13 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred generate_det_lookup_goal(list(prog_var)::in, pred_id::in, proc_id::in,
-	term__context::in, map(prog_var, type)::in, map(prog_var, type)::out,
+:- pred generate_simple_lookup_goal(list(prog_var)::in,
+	pred_id::in, proc_id::in, term__context::in,
+	map(prog_var, type)::in, map(prog_var, type)::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
 	prog_var::out, hlds_goal::out) is det.
 
-generate_det_lookup_goal(Vars, PredId, ProcId, Context, VarTypes0, VarTypes,
+generate_simple_lookup_goal(Vars, PredId, ProcId, Context, VarTypes0, VarTypes,
 		VarSet0, VarSet, TableInfo0, TableInfo, TableVar, Goal) :-
 
 	generate_get_table_goal(PredId, ProcId, VarTypes0, VarTypes1,
@@ -663,7 +668,10 @@
 	set__singleton_set(NonLocals0, TableVar),
 	set__insert_list(NonLocals0, Vars, NonLocals),
 	instmap_delta_from_assoc_list([], InstMapDelta),
-	init_goal_info(NonLocals, InstMapDelta, det, Context, GoalInfo),
+	init_goal_info(NonLocals, InstMapDelta, det, Context, GoalInfo0),
+	goal_info_get_features(GoalInfo0, Features0),
+	set__insert(Features0, call_table_gen, Features),
+	goal_info_set_features(GoalInfo0, Features, GoalInfo),
 	Goal = GoalEx - GoalInfo.
 
 :- pred generate_non_lookup_goal(list(prog_var)::in, pred_id::in, proc_id::in,
@@ -692,7 +700,10 @@
 	set__insert_list(NonLocals0, Vars, NonLocals),
 	create_instmap_delta(Goals, InstMapDelta0),
 	instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
-	init_goal_info(NonLocals, InstMapDelta, det, Context, GoalInfo),
+	init_goal_info(NonLocals, InstMapDelta, det, Context, GoalInfo0),
+	goal_info_get_features(GoalInfo0, Features0),
+	set__insert(Features0, call_table_gen, Features),
+	goal_info_set_features(GoalInfo0, Features, GoalInfo),
 	Goal = GoalEx - GoalInfo.
 
 :- pred generate_lookup_goals(list(prog_var)::in, term__context::in,
Index: compiler/trace.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/trace.m,v
retrieving revision 1.29
diff -u -b -r1.29 trace.m
--- compiler/trace.m	1999/12/16 19:06:52	1.29
+++ compiler/trace.m	2000/01/15 04:46:24
@@ -88,13 +88,28 @@
 					% trees for the declarative debugger.
 					% Otherwise, it will be no.
 
-			maybe(int)	% If --use-trail is set, this will
+			maybe(int),	% If --use-trail is set, this will
 					% be yes(M), where stack slots M
 					% and M+1 are the slots that hold the
 					% saved values of the trail pointer
 					% and the ticket counter respectively
 					% at the time of the call. Otherwise,
 					% it will be no.
+
+			maybe(int),	% If the procedure lives on the det
+					% stack but creates temporary frames
+					% on the nondet stack, this will be
+					% yes(M), where stack slot M is
+					% reserved to hold the value of maxfr
+					% at the time of the call. Otherwise,
+					% it will be no.
+
+			maybe(int)	% If the procedure's evaluation method
+					% is memo, loopcheck or minimal model, 
+					% this will be yes(M), where stack slot
+					% M holds the variable that represents
+					% the tip of the call table. Otherwise,
+					% it will be no.
 		).
 
 	% Return the set of input variables whose values should be preserved
@@ -106,17 +121,27 @@
 :- pred trace__fail_vars(module_info::in, proc_info::in,
 		set(prog_var)::out) is det.
 
+	% Figure out whether we need a slot for storing the value of maxfr
+	% on entry, and record the result in the proc info.
+:- pred trace__do_we_need_maxfr_slot(globals::in, proc_info::in,
+	proc_info::out) is det.
+
 	% Return the number of slots reserved for tracing information.
 	% If there are N slots, the reserved slots will be 1 through N.
-:- pred trace__reserved_slots(proc_info::in, globals::in, int::out) is det.
+	%
+	% It is possible that one of these reserved slots contains a variable.
+	% If so, the variable and its slot number are returned in the last
+	% argument.
+:- pred trace__reserved_slots(proc_info::in, globals::in, int::out,
+	maybe(pair(prog_var, int))::out) is det.
 
 	% Construct and return an abstract struct that represents the
 	% tracing-specific part of the code generator state. Return also
 	% info about the non-fixed slots used by the tracing system,
 	% for eventual use in the constructing the procedure's layout
 	% structure.
-:- pred trace__setup(globals::in, trace_slot_info::out, trace_info::out,
-	code_info::in, code_info::out) is det.
+:- pred trace__setup(proc_info::in, globals::in, trace_slot_info::out,
+	trace_info::out, code_info::in, code_info::out) is det.
 
 	% Generate code to fill in the reserved stack slots.
 :- pred trace__generate_slot_fill_code(trace_info::in, code_tree::out,
@@ -167,9 +192,9 @@
 
 :- implementation.
 
-:- import_module continuation_info, type_util, llds_out, tree, varset.
+:- import_module continuation_info, type_util, llds_out, tree, code_util.
 :- import_module (inst), instmap, inst_match, mode_util, options.
-:- import_module list, bool, int, string, map, std_util, require, term.
+:- import_module list, bool, int, string, map, std_util, require, varset.
 
 	% Information specific to a trace port.
 :- type trace_port_info
@@ -206,9 +231,24 @@
 		error("length mismatch in trace__fail_vars")
 	).
 
+trace__do_we_need_maxfr_slot(Globals, ProcInfo0, ProcInfo) :-
+	globals__get_trace_level(Globals, TraceLevel),
+	proc_info_interface_code_model(ProcInfo0, CodeModel),
+	(
+		TraceLevel \= none,
+		CodeModel \= model_non,
+		proc_info_goal(ProcInfo0, Goal),
+		code_util__goal_may_alloc_temp_frame(Goal)
+	->
+		MaxfrFlag = yes
+	;
+		MaxfrFlag = no
+	),
+	proc_info_set_maxfr_slot_flag(ProcInfo0, MaxfrFlag, ProcInfo).
+
 	% trace__reserved_slots and trace__setup cooperate in the allocation
-	% of stack slots for tracing purposes. The allocation is done in five
-	% stages.
+	% of stack slots for tracing purposes. The allocation is done in the
+	% following stages.
 	%
 	% stage 1:	Allocate the fixed slots, slots 1, 2 and 3, to hold
 	%		the event number of call, the call sequence number
@@ -239,12 +279,23 @@
 	%		in the proc layout; if there are no such slots, that
 	%		field will contain -1.
 	%
-	% The runtime system cannot know whether the stack frame has a slot
-	% that holds the saved from-full flag and whether it has the slots
-	% for the proof tree. This is why trace__setup returns TraceSlotInfo,
-	% which answers these questions, for later inclusion in the
-	% procedure's layout structure.
+	% stage 6:	If the procedure lives on the det stack but can put
+	%		frames on the nondet stack, allocate a slot to hold
+	%		the saved value of maxfr at the point of the call,
+	%		for use in implementing retry. The number of this
+	%		slot is recorded in the maybe_maxfr field in the proc
+	%		layout; if there is no such slot, that field will
+	%		contain -1.
 	%
+	% stage 7:	If the procedure's evaluation method is memo, loopcheck
+	%		or minimal model, we allocate a slot to hold the
+	%		variable that represents the tip of the call table.
+	%		The debugger needs this, because when it executes a
+	%		retry command, it must reset this tip to uninitialized.
+	%		The number of this slot is recorded in the maybe_table
+	%		field in the proc layout; if there is no such slot,
+	%		that field will contain -1.
+	%
 	% The procedure's layout structure does not need to include
 	% information about the presence or absence of the slot holding
 	% the address of the redo layout structure. If we generate redo
@@ -260,13 +311,22 @@
 	% their redos thus checks this slot to see whether it can (or should)
 	% access the other slots. In shallow-traced model_non procedures
 	% that generate redo events, the from-full flag is always in slot 5.
+	%
+	% The slots allocated by stages 1 and 2 are only ever referred to
+	% by the runtime system if they are guaranteed to exist. The runtime
+	% system may of course also need to refer to slots allocated by later
+	% stages, but before it does so, it needs to know whether those slots
+	% exist or not. This is why trace__setup returns TraceSlotInfo,
+	% which answers such questions, for later inclusion in the
+	% procedure's layout structure.
 
-trace__reserved_slots(ProcInfo, Globals, ReservedSlots) :-
+trace__reserved_slots(ProcInfo, Globals, ReservedSlots, MaybeTableVarInfo) :-
 	globals__get_trace_level(Globals, TraceLevel),
 	(
 		TraceLevel = none
 	->
-		ReservedSlots = 0
+		ReservedSlots = 0,
+		MaybeTableVarInfo = no
 	;
 		Fixed = 3, % event#, call#, call depth
 		(
@@ -294,11 +354,25 @@
 		;
 			Trail = 0
 		),
-		ReservedSlots is Fixed + RedoLayout + FromFull + DeclDebug +
-			Trail
+		proc_info_get_maxfr_slot_flag(ProcInfo, MaxfrFlag),
+		( MaxfrFlag = yes ->
+			Maxfr = 1
+		;
+			Maxfr = 0
+		),
+		ReservedSlots0 = Fixed + RedoLayout + FromFull + DeclDebug +
+			Trail + Maxfr,
+		proc_info_get_call_table_tip(ProcInfo, MaybeCallTableVar),
+		( MaybeCallTableVar = yes(CallTableVar) ->
+			ReservedSlots = ReservedSlots0 + 1,
+			MaybeTableVarInfo = yes(CallTableVar - ReservedSlots)
+		;
+			ReservedSlots = ReservedSlots0,
+			MaybeTableVarInfo = no
+		)
 	).
 
-trace__setup(Globals, TraceSlotInfo, TraceInfo) -->
+trace__setup(ProcInfo, Globals, TraceSlotInfo, TraceInfo) -->
 	code_info__get_proc_model(CodeModel),
 	{ globals__lookup_bool_option(Globals, trace_decl, TraceDecl) },
 	{ globals__lookup_bool_option(Globals, trace_redo, TraceRedo) },
@@ -348,15 +422,44 @@
 			TrailLval =  stackvar(NextSlotAfterDecl),
 			TicketLval = stackvar(NextSlotAfterDecl+1)
 		),
-		MaybeTrailLvals = yes(TrailLval - TicketLval)
+		MaybeTrailLvals = yes(TrailLval - TicketLval),
+		NextSlotAfterTrail = NextSlotAfterDecl + 2
 	;
 		MaybeTrailSlot = no,
-		MaybeTrailLvals = no
+		MaybeTrailLvals = no,
+		NextSlotAfterTrail = NextSlotAfterDecl
+	},
+	{ proc_info_get_maxfr_slot_flag(ProcInfo, yes) ->
+		MaybeMaxfrSlot = yes(NextSlotAfterTrail),
+		( CodeModel = model_non ->
+			MaxfrLval =  framevar(NextSlotAfterTrail)
+		;
+			MaxfrLval =  stackvar(NextSlotAfterTrail)
+		),
+		MaybeMaxfrLval = yes(MaxfrLval),
+		NextSlotAfterMaxfr = NextSlotAfterTrail + 1
+	;
+		MaybeMaxfrSlot = no,
+		MaybeMaxfrLval = no,
+		NextSlotAfterMaxfr = NextSlotAfterTrail
+	},
+	{ proc_info_get_call_table_tip(ProcInfo, yes(_)) ->
+		MaybeCallTableSlot = yes(NextSlotAfterMaxfr),
+		( CodeModel = model_non ->
+			CallTableLval =  framevar(NextSlotAfterMaxfr)
+		;
+			CallTableLval =  stackvar(NextSlotAfterMaxfr)
+		),
+		MaybeCallTableLval = yes(CallTableLval)
+	;
+		MaybeCallTableSlot = no,
+		MaybeCallTableLval = no
 	},
-	{ TraceSlotInfo = trace_slot_info(MaybeFromFullSlot,
-		MaybeDeclSlots, MaybeTrailSlot) },
+	{ TraceSlotInfo = trace_slot_info(MaybeFromFullSlot, MaybeDeclSlots,
+		MaybeTrailSlot, MaybeMaxfrSlot, MaybeCallTableSlot) },
 	{ init_trace_info(TraceType, TraceInternal, TraceDecl, MaybeTrailLvals,
-		MaybeRedoLayout, TraceInfo) }.
+		MaybeMaxfrLval, MaybeCallTableLval, MaybeRedoLayout,
+		TraceInfo) }.
 
 trace__generate_slot_fill_code(TraceInfo, TraceCode) -->
 	code_info__get_proc_model(CodeModel),
@@ -364,6 +467,8 @@
 	trace_info_get_trace_type(TraceInfo, TraceType),
 	trace_info_get_maybe_redo_layout_slot(TraceInfo, MaybeRedoLayoutSlot),
 	trace_info_get_maybe_trail_slots(TraceInfo, MaybeTrailLvals),
+	trace_info_get_maybe_maxfr_slot(TraceInfo, MaybeMaxfrLval),
+	trace_info_get_maybe_call_table_slot(TraceInfo, MaybeCallTableLval),
 	trace__event_num_slot(CodeModel, EventNumLval),
 	trace__call_num_slot(CodeModel, CallNumLval),
 	trace__call_depth_slot(CodeModel, CallDepthLval),
@@ -400,10 +505,25 @@
 			FillFourSlots, "\n",
 			"\t\tMR_mark_ticket_stack(", TicketLvalStr, ");\n",
 			"\t\tMR_store_ticket(", TrailLvalStr, ");"
-		], FillAllSlots)
+		], FillSixSlots)
 	;
 		MaybeTrailLvals = no,
-		FillAllSlots = FillFourSlots
+		FillSixSlots = FillFourSlots
+	),
+	(
+		% This could be done by generating proper LLDS instead of C.
+		% However, in shallow traced code we want to execute this
+		% only when the caller is deep traced, and everything inside
+		% that test must be in C code.
+		MaybeMaxfrLval = yes(MaxfrLval),
+		trace__stackref_to_string(MaxfrLval, MaxfrLvalStr),
+		string__append_list([
+			FillSixSlots,
+			"\n\t\t", MaxfrLvalStr, " = (Word) MR_maxfr;"
+		], FillCondSlots)
+	;
+		MaybeMaxfrLval = no,
+		FillCondSlots = FillSixSlots
 	),
 	(
 		TraceType = shallow_trace(CallFromFullSlot),
@@ -412,19 +532,34 @@
 		string__append_list([
 			"\t\t", CallFromFullSlotStr, " = MR_trace_from_full;\n",
 			"\t\tif (MR_trace_from_full) {\n",
-			FillAllSlots, "\n",
+			FillCondSlots, "\n",
 			"\t\t} else {\n",
 			"\t\t\t", CallDepthStr, " = MR_trace_call_depth;\n",
 			"\t\t}"
-		], TraceStmt)
+		], TraceStmt1)
 	;
 		TraceType = deep_trace,
-		TraceStmt = FillAllSlots
+		TraceStmt1 = FillCondSlots
 	),
-	TraceCode = node([
-		pragma_c([], [pragma_c_raw_code(TraceStmt)],
+	TraceCode1 = node([
+		pragma_c([], [pragma_c_raw_code(TraceStmt1)],
 			will_not_call_mercury, no, no, yes) - ""
+	]),
+	(
+		MaybeCallTableLval = yes(CallTableLval),
+		trace__stackref_to_string(CallTableLval, CallTableLvalStr),
+		string__append_list([
+			"\t\t", CallTableLvalStr, " = 0;"
+		], TraceStmt2),
+		TraceCode2 = node([
+			pragma_c([], [pragma_c_raw_code(TraceStmt2)],
+				will_not_call_mercury, no, no, yes) - ""
 	])
+	;
+		MaybeCallTableLval = no,
+		TraceCode2 = empty
+	),
+	TraceCode = tree(TraceCode1, TraceCode2)
 	}.
 
 trace__prepare_for_call(TraceCode) -->
@@ -860,6 +995,13 @@
 					% of the slots that hold the value
 					% of the trail pointer and the ticket
 					% counter at the time of the call.
+			maybe(lval),	% If we reserve a slot for holding
+					% the value of maxfr at entry for use
+					% in implementing retry, the lval of
+					% the slot.
+			maybe(lval),	% If we reserve a slot for holding
+					% the value of the call table tip
+					% variable, the lval of this variable.
 			maybe(label)	% If we are generating redo events,
 					% this has the label associated with
 					% the fail event, which we then reserve
@@ -871,26 +1013,35 @@
 		).
 
 :- pred init_trace_info(trace_type::in, bool::in, bool::in,
-	maybe(pair(lval))::in, maybe(label)::in, trace_info::out) is det.
+	maybe(pair(lval))::in, maybe(lval)::in, maybe(lval)::in,
+	maybe(label)::in, trace_info::out) is det.
 
 :- pred trace_info_get_trace_type(trace_info::in, trace_type::out) is det.
 :- pred trace_info_get_trace_internal(trace_info::in, bool::out) is det.
 :- pred trace_info_get_trace_decl(trace_info::in, bool::out) is det.
 :- pred trace_info_get_maybe_trail_slots(trace_info::in,
 	maybe(pair(lval))::out) is det.
+:- pred trace_info_get_maybe_maxfr_slot(trace_info::in,
+	maybe(lval)::out) is det.
+:- pred trace_info_get_maybe_call_table_slot(trace_info::in,
+	maybe(lval)::out) is det.
 :- pred trace_info_get_maybe_redo_layout_slot(trace_info::in,
 	maybe(label)::out) is det.
 
 init_trace_info(TraceType, TraceInternal, TraceDecl,
-	MaybeTrailSlot, MaybeRedoLayoutSlot,
-	trace_info(TraceType, TraceInternal, TraceDecl,
-		MaybeTrailSlot, MaybeRedoLayoutSlot)).
+	MaybeTrailLvals, MaybeMaxfrLval, MaybeCallTable, MaybeRedoLayout,
+	trace_info(TraceType, TraceInternal, TraceDecl, MaybeTrailLvals,
+		MaybeMaxfrLval, MaybeCallTable, MaybeRedoLayout)).
 
-trace_info_get_trace_type(trace_info(TraceType, _, _, _, _), TraceType).
-trace_info_get_trace_internal(trace_info(_, TraceInternal, _, _, _),
+trace_info_get_trace_type(trace_info(TraceType, _, _, _, _, _, _), TraceType).
+trace_info_get_trace_internal(trace_info(_, TraceInternal, _, _, _, _, _),
 	TraceInternal).
-trace_info_get_trace_decl(trace_info(_, _, TraceDecl, _, _), TraceDecl).
-trace_info_get_maybe_trail_slots(trace_info(_, _, _, MaybesTrailSlot, _),
-	MaybesTrailSlot).
-trace_info_get_maybe_redo_layout_slot(trace_info(_, _, _, _,
-	MaybeRedoLayoutSlot), MaybeRedoLayoutSlot).
+trace_info_get_trace_decl(trace_info(_, _, TraceDecl, _, _, _, _), TraceDecl).
+trace_info_get_maybe_trail_slots(trace_info(_, _, _, MaybeTrailLvals, _, _, _),
+	MaybeTrailLvals).
+trace_info_get_maybe_maxfr_slot(trace_info(_, _, _, _, MaybeMaxfrLval, _, _),
+	MaybeMaxfrLval).
+trace_info_get_maybe_call_table_slot(trace_info(_, _, _, _, _,
+	MaybeCallTable, _), MaybeCallTable).
+trace_info_get_maybe_redo_layout_slot(trace_info(_, _, _, _, _, _,
+	MaybeRedoLayout), MaybeRedoLayout).
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing doc
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.200
diff -u -b -r1.200 user_guide.texi
--- doc/user_guide.texi	2000/01/10 00:43:58	1.200
+++ doc/user_guide.texi	2000/01/15 04:49:25
@@ -1801,11 +1801,29 @@
 By default, this command is strict, and it uses the default print level.
 @sp 1
 @item finish [-NSans] [@var{num}]
-Continues execution until it reaches a final (EXIT or FAIL) port of
-the @var{num}'th ancestor of the call to which the current event refers.
+Continues execution until it reaches a final (EXIT, FAIL, or EXCEPTION) port
+of the @var{num}'th ancestor of the call to which the current event refers.
 The default value of @var{num} is zero,
 which means skipping to the end of the current call.
 Reports an error if execution is already at the desired port.
+ at sp 1
+The options @samp{-n} or @samp{--none}, @samp{-s} or @samp{--some},
+ at samp{-a} or @samp{--all} specify the print level to use
+for the duration of the command,
+while the options @samp{-S} or @samp{--strict}
+and @samp{-N} or @samp{--nostrict} specify
+the strictness of the command.
+ at sp 1
+By default, this command is strict, and it uses the default print level.
+ at sp 1
+ at item fail [-NSans] [@var{num}]
+Continues execution until it reaches a FAIL or EXCEPTION port
+of the @var{num}'th ancestor of the call to which the current event refers.
+The default value of @var{num} is zero,
+which means skipping to the failure of the current call.
+Reports an error if execution is already at the desired port,
+or if the determinism of the selected call
+does not guarantee that it will eventually fail.
 @sp 1
 The options @samp{-n} or @samp{--none}, @samp{-s} or @samp{--some},
 @samp{-a} or @samp{--all} specify the print level to use
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing library
cvs diff: Diffing profiler
cvs diff: Diffing runtime
Index: runtime/mercury_stack_layout.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_layout.h,v
retrieving revision 1.35
diff -u -b -r1.35 mercury_stack_layout.h
--- runtime/mercury_stack_layout.h	1999/12/16 11:39:22	1.35
+++ runtime/mercury_stack_layout.h	2000/01/15 04:51:04
@@ -366,6 +366,13 @@
 	MR_Stack_Layout_Compiler_Proc	MR_proc_comp;
 } MR_Stack_Layout_Proc_Id;
 
+typedef	enum {
+	MR_EVAL_METHOD_NORMAL,
+	MR_EVAL_METHOD_LOOP_CHECK,
+	MR_EVAL_METHOD_MEMO,
+	MR_EVAL_METHOD_MINIMAL
+} MR_EvalMethod;
+
 typedef	struct MR_Stack_Layout_Entry_Struct {
 	/* stack traversal group */
 	Code			*MR_sle_code_addr;
@@ -384,6 +391,17 @@
 	MR_int_least16_t	MR_sle_max_r_num;
 	MR_int_least8_t		MR_sle_maybe_from_full;
 	MR_int_least8_t		MR_sle_maybe_trail;
+				/*
+				** the eval method field is actually of type
+				** MR_EvalMethod. We declare it as of type
+				** MR_int_least8_t in order to make sure that
+				** the size allocated for the field by the C
+				** compiler matches the expectations of
+				** stack_layout.m.
+				*/
+	MR_int_least8_t		MR_sle_maybe_maxfr;
+	MR_int_least8_t		MR_sle_eval_method;
+	MR_int_least8_t		MR_sle_maybe_call_table;
 	MR_int_least8_t		MR_sle_maybe_decl_debug;
 } MR_Stack_Layout_Entry;
 
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
Index: tests/debugger/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/Mmakefile,v
retrieving revision 1.34
diff -u -b -r1.34 Mmakefile
--- tests/debugger/Mmakefile	1999/12/21 01:23:42	1.34
+++ tests/debugger/Mmakefile	2000/01/15 04:53:17
@@ -28,6 +28,7 @@
 	mdb_command_test		\
 	multi_parameter			\
 	queens				\
+	retry				\
 	shallow
 
 # The following tests are disabled, since currently they get some spurious
Index: tests/debugger/mdb_command_test.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/mdb_command_test.inp,v
retrieving revision 1.7
diff -u -b -r1.7 mdb_command_test.inp
--- tests/debugger/mdb_command_test.inp	1999/11/15 00:43:47	1.7
+++ tests/debugger/mdb_command_test.inp	2000/01/15 04:53:05
@@ -4,6 +4,7 @@
 step                 xyzzy xyzzy xyzzy xyzzy xyzzy
 goto                 xyzzy xyzzy xyzzy xyzzy xyzzy
 finish               xyzzy xyzzy xyzzy xyzzy xyzzy
+fail                 xyzzy xyzzy xyzzy xyzzy xyzzy
 return               xyzzy xyzzy xyzzy xyzzy xyzzy
 forward              xyzzy xyzzy xyzzy xyzzy xyzzy
 mindepth             xyzzy xyzzy xyzzy xyzzy xyzzy
Index: tests/debugger/queens.exp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/queens.exp,v
retrieving revision 1.17
diff -u -b -r1.17 queens.exp
--- tests/debugger/queens.exp	1999/11/20 01:03:26	1.17
+++ tests/debugger/queens.exp	2000/01/15 04:53:04
@@ -134,8 +134,6 @@
       21:     10  6 SWTC queens.m:46
                          pred queens:qperm/2-0 (nondet) s1;
 mdb> retry
-      34:     10  6 EXIT queens.m:45 (from queens.m:49)
-                         pred queens:qperm/2-0 (nondet)
       20:     10  6 CALL queens.m:45 (from queens.m:49)
                          pred queens:qperm/2-0 (nondet)
 mdb> print *
@@ -231,8 +229,6 @@
 mdb> disable 1
  1: - stop  interface pred queens:qdelete/3-0 (nondet)
 mdb> retry 4
-      76:      4  3 EXIT queens.m:45 (from queens.m:42)
-                         pred queens:qperm/2-0 (nondet)
        5:      4  3 CALL queens.m:45 (from queens.m:42)
                          pred queens:qperm/2-0 (nondet)
 mdb> break 49
Index: tests/debugger/retry.exp
===================================================================
RCS file: retry.exp
diff -N retry.exp
Index: tests/debugger/retry.inp
===================================================================
RCS file: retry.inp
diff -N retry.inp
--- /dev/null	Thu Mar  4 04:20:11 1999
+++ retry.inp	Sat Jan 15 15:53:17 2000
@@ -0,0 +1,35 @@
+echo on
+register --quiet
+break det_without_cut_1
+continue -a
+disable 1
+retry
+stack
+finish
+retry 1
+stack
+break det_without_cut_2
+continue -a
+delete 1
+retry 2
+finish
+stack
+break det_with_cut_1
+continue -a
+delete 1
+finish
+retry
+finish
+stack
+retry 1
+break det_with_cut_2
+continue -a
+delete 1
+break fib
+continue
+continue
+continue
+continue
+step
+retry 2
+continue -S
Index: tests/debugger/retry.m
===================================================================
RCS file: retry.m
diff -N retry.m
--- /dev/null	Thu Mar  4 04:20:11 1999
+++ retry.m	Sat Jan 15 15:53:06 2000
@@ -0,0 +1,131 @@
+:- module retry.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- import_module std_util, list, int.
+
+main -->
+	{
+		det_without_cut(1, A),
+		det_with_cut(2, B),
+		det_with_cut(3, C),
+		solutions(nondet(4), Ds),
+		solutions(nondet(5), Es)
+	},
+	output(A),
+	output(B),
+	output(C),
+	outputs(Ds),
+	outputs(Es),
+	{ fib(15, F) },
+	output(F).
+
+%---------------------------------------------------------------------------%
+
+:- pred det_without_cut(int::in, int::out) is det.
+
+det_without_cut(X0, X) :-
+	det_without_cut_1(X0 + 2, X).
+
+:- pred det_without_cut_1(int::in, int::out) is det.
+
+det_without_cut_1(X0, X1 * 2) :-
+	det_without_cut_2(X0, X1).
+
+:- pred det_without_cut_2(int::in, int::out) is det.
+
+det_without_cut_2(X, X).
+
+%---------------------------------------------------------------------------%
+
+:- pred det_with_cut(int::in, int::out) is det.
+
+det_with_cut(X0, X) :-
+	( det_with_cut_1(X0, _) ->
+		X = X0 * 2
+	;
+		X = X0 * 3
+	).
+
+:- pred det_with_cut_1(int::in, int::out) is nondet.
+
+det_with_cut_1(X0, X) :-
+	X0 = 2,
+	(
+		X = 10
+	;
+		det_with_cut_2(15, X)
+	).
+
+:- pred det_with_cut_2(int::in, int::out) is det.
+
+det_with_cut_2(X, X).
+
+%---------------------------------------------------------------------------%
+
+:- pred nondet(int::in, int::out) is multi.
+
+nondet(X0, X) :-
+	nondet_1(X0, X1),
+	nondet_2(X1, X2),
+	( X2 < 75 ->
+		X = X2
+	;
+		X = 2 * X2
+	).
+
+:- pred nondet_1(int::in, int::out) is multi.
+
+nondet_1(X0, X) :-
+	X1 = 10 * X0,
+	(
+		X = X1
+	;
+		X = X1 + 1
+	).
+
+:- pred nondet_2(int::in, int::out) is det.
+
+nondet_2(X, X).
+
+%---------------------------------------------------------------------------%
+
+:- pred fib(int::in, int::out) is det.
+:- pragma memo(fib/2).
+
+fib(N, F) :-
+	( N < 2 ->
+		F = 1
+	;
+		fib(N - 1, F1),
+		fib(N - 2, F2),
+		F is F1 + F2
+	).
+
+%---------------------------------------------------------------------------%
+
+:- pred output(int::in, io__state::di, io__state::uo) is det.
+
+output(X) -->
+	io__write_int(X),
+	io__write_string("\n").
+
+:- pred outputs(list(int)::in, io__state::di, io__state::uo) is det.
+
+outputs(Xs) -->
+	outputs1(Xs),
+	io__write_string("\n").
+
+:- pred outputs1(list(int)::in, io__state::di, io__state::uo) is det.
+
+outputs1([]) --> [].
+outputs1([X | Xs]) -->
+	io__write_int(X),
+	io__write_string(" "),
+	outputs1(Xs).
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/mercury_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace.c,v
retrieving revision 1.20
diff -u -b -r1.20 mercury_trace.c
--- trace/mercury_trace.c	1999/12/20 14:04:03	1.20
+++ trace/mercury_trace.c	2000/01/15 04:45:47
@@ -61,10 +61,30 @@
 static	Code	*MR_trace_event(MR_Trace_Cmd_Info *cmd, bool interactive,
 			const MR_Stack_Layout_Label *layout,
 			MR_Trace_Port port, Unsigned seqno, Unsigned depth);
+static	const MR_Stack_Layout_Entry *MR_unwind_stacks_for_retry(
+			const MR_Stack_Layout_Label *top_layout,
+			int ancestor_level, Word **base_sp_ptr,
+			Word **base_curfr_ptr, Word **base_maxfr_ptr,
+			const char **problem);
+static	const char *MR_undo_updates_of_maxfr(const MR_Stack_Layout_Entry
+			*level_layout, Word *sp, Word *curfr,
+			Word **maxfr_ptr);
 static	Word	MR_trace_find_input_arg(const MR_Stack_Layout_Label *label, 
-			Word *saved_regs, MR_uint_least16_t var_num,
-			bool *succeeded);
+			Word *saved_regs, Word *base_sp, Word *base_curfr,
+			MR_uint_least16_t var_num, bool *succeeded);
 
+#ifdef	MR_USE_MINIMAL_MODEL
+static	MR_Retry_Result MR_check_minimal_model_calls(MR_Event_Info *event_info,
+			int ancestor_level, Word *target_maxfr,
+			const char **problem);
+#endif
+
+static	void	MR_init_call_table_array(void);
+static	void	MR_maybe_record_call_table(const MR_Stack_Layout_Entry
+			*level_layout, Word *sp, Word *curfr);
+static	void	MR_reset_call_table_array(void);
+static	void	MR_abandon_call_table_array(void);
+
 /*
 ** Reserve room for event counts for this many depths initially.
 */
@@ -145,6 +165,23 @@
 				}
 			}
 
+		case MR_CMD_FAIL:
+			if (MR_trace_ctrl.MR_trace_stop_depth != depth) {
+				goto check_stop_print;
+			} else {
+				port = (MR_Trace_Port) layout->MR_sll_port;
+
+				if (port == MR_PORT_FAIL ||
+					port == MR_PORT_EXCEPTION)
+				{
+					return MR_trace_event(&MR_trace_ctrl,
+						TRUE, layout, port,
+						seqno, depth);
+				} else {
+					goto check_stop_print;
+				}
+			}
+
 		case MR_CMD_GOTO:
 			if (MR_trace_event_number >=
 					MR_trace_ctrl.MR_trace_stop_event)
@@ -371,12 +408,21 @@
 	MR_copy_saved_regs_to_regs(event_info.MR_max_mr_num, saved_regs);
 	return jumpaddr;
 }
+
+/*****************************************************************************/
 
-const char *
+/* The initial size of arrays of argument values. */
+#define	MR_INIT_ARG_COUNT	20
+
+MR_Retry_Result
 MR_trace_retry(MR_Event_Info *event_info, MR_Event_Details *event_details,
-	Code **jumpaddr)
+	int ancestor_level, const char **problem, Code **jumpaddr)
 {
-	const MR_Stack_Layout_Entry	*entry;
+	Word				*base_sp;
+	Word				*base_curfr;
+	Word				*base_maxfr;
+	const MR_Stack_Layout_Label	*top_layout;
+	const MR_Stack_Layout_Entry	*level_layout;
 	const MR_Stack_Layout_Label	*call_label;
 	const MR_Stack_Layout_Vars	*input_args;
 	Word				*args;
@@ -385,23 +431,41 @@
 	Word				arg_value;
 	int				i;
 	bool				succeeded;
-	const char			*message;
 	Word 				*saved_regs;
+#ifdef	MR_USE_MINIMAL_MODEL
+	MR_Retry_Result			result;
+#endif
+
+	args = NULL;
+	MR_init_call_table_array();
 
 	saved_regs = event_info->MR_saved_regs;
-	entry = event_info->MR_event_sll->MR_sll_entry;
-	if (!MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(entry)) {
-		message = "Cannot perform retry, because this procedure "
-			"was not compiled with\nexecution tracing enabled.";
-		return message;
+	top_layout = event_info->MR_event_sll;
+	*problem = NULL;
+	base_sp = MR_saved_sp(saved_regs);
+	base_curfr = MR_saved_curfr(saved_regs);
+	base_maxfr = MR_saved_maxfr(saved_regs);
+	level_layout = MR_unwind_stacks_for_retry(top_layout, ancestor_level,
+			&base_sp, &base_curfr, &base_maxfr, problem);
+
+	if (level_layout == NULL) {
+		if (*problem == NULL) {
+			*problem = "MR_unwind_stacks_for_retry failed "
+					"without reporting a problem";
+		}
+
+		goto report_problem;
+	} else if (! MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(level_layout)) {
+		*problem = "that procedure does not have debugging information";
+		goto report_problem;
 	}
 
-	call_label = entry->MR_sle_call_label;
+	call_label = level_layout->MR_sle_call_label;
 	input_args = &call_label->MR_sll_var_info;
 	if (input_args->MR_slvs_var_count < 0) {
-		message = "Cannot perform retry because information about "
+		*problem = "Cannot perform retry because information about "
 		          "the input arguments is not available.";
-		return message;
+		goto report_problem;
 	}
 
 	/*
@@ -412,19 +476,18 @@
 	** no native garbage collection can be triggered.
 	*/
 
-	args = NULL;
 	arg_max = 0;
 
 	for (i = 0; i < MR_all_desc_var_count(input_args); i++) {
 		arg_value = MR_trace_find_input_arg(event_info->MR_event_sll,
-				saved_regs,
+				saved_regs, base_sp, base_curfr,
 				input_args->MR_slvs_names[i].MR_var_num,
 				&succeeded);
 
 		if (! succeeded) {
-			message = "Cannot perform retry because the values of "
-				  "some input arguments are missing.";
-			return message;
+			*problem = "Cannot perform retry because the values "
+				  "of some input arguments are missing.";
+			goto report_problem;
 		}
 
 		if (i < MR_long_desc_var_count(input_args)) {
@@ -444,21 +507,50 @@
 		}
 	}
 
-	MR_trace_call_seqno = event_info->MR_call_seqno - 1;
-	MR_trace_call_depth = event_info->MR_call_depth - 1;
+#ifdef	MR_USE_MINIMAL_MODEL
 
-	if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
-		MR_Long_Lval	location;
-		Word		*this_frame;
+	result = MR_check_minimal_model_calls(event_info, ancestor_level,
+			base_maxfr, problem);
+
+	switch (result) {
+	case MR_RETRY_OK_DIRECT:
+		/* we just go on to the code below */
+		break;
+
+	case MR_RETRY_OK_FINISH_FIRST:
+	case MR_RETRY_OK_FAIL_FIRST:
+		MR_abandon_call_table_array();
+		return result;
+
+	case MR_RETRY_ERROR:
+	default:
+		if (*problem == NULL) {
+			*problem = "MR_check_minimal_model_calls failed "
+					"without reporting problem";
+		}
+
+		goto report_problem;
+	}
+
+#endif	/* MR_USE_MINIMAL_MODEL */
 
 		/*
-		** We are at a final port, so both curfr and maxfr
-		** must already have been reset to their original values.
-		** We only need to set up the succip register for the "call",
-		** and then remove this frame from the det stack.
+	** At this point, we are now sure that we can carry out the retry
+	** operation directly. Before we were sure, we couldn't modify the
+	** environment (i.e. the stacks, the saved registers, and the relevant
+	** call tables). Now, however, we can set up the environment to make
+	** it reflect its state at the time of the entry to the retried call.
 		*/
+
+	MR_saved_sp(saved_regs) = base_sp;
+	MR_saved_curfr(saved_regs) = base_curfr;
+	MR_saved_maxfr(saved_regs) = base_maxfr;
+
+	if (MR_DETISM_DET_STACK(level_layout->MR_sle_detism)) {
+		MR_Long_Lval	location;
+		Word		*this_frame;
 
-		location = entry->MR_sle_succip_locn;
+		location = level_layout->MR_sle_succip_locn;
 		if (MR_LONG_LVAL_TYPE(location) != MR_LONG_LVAL_TYPE_STACKVAR)
 		{
 			fatal_error("illegal location for stored succip");
@@ -468,18 +560,20 @@
 		MR_saved_succip(saved_regs) = (Word *)
 				MR_based_stackvar(this_frame,
 				MR_LONG_LVAL_NUMBER(location));
-		MR_saved_sp(saved_regs) -= entry->MR_sle_stack_slots;
+		MR_saved_sp(saved_regs) -= level_layout->MR_sle_stack_slots;
 		MR_trace_event_number = MR_event_num_stackvar(this_frame);
+		MR_trace_call_seqno = MR_call_num_stackvar(this_frame) - 1;
+		MR_trace_call_depth = MR_call_depth_stackvar(this_frame) - 1;
 
 #ifdef	MR_USE_TRAIL
-		if (entry->MR_sle_maybe_trail >= 0) {
+		if (level_layout->MR_sle_maybe_trail >= 0) {
 			Word	ticket_counter;
 			Word	trail_ptr;
 
 			trail_ptr = MR_based_stackvar(this_frame,
-					entry->MR_sle_maybe_trail);
+					level_layout->MR_sle_maybe_trail);
 			ticket_counter = MR_based_stackvar(this_frame,
-					entry->MR_sle_maybe_trail+1);
+					level_layout->MR_sle_maybe_trail+1);
 			MR_reset_ticket(trail_ptr, MR_retry);
 			MR_discard_tickets_to(ticket_counter);
 		} else {
@@ -489,29 +583,23 @@
 	} else {
 		Word	*this_frame;
 
-		/*
-		** We are at a final port, so sp must already have been reset
-		** to its original value. We only need to set up the succip
-		** and curfr registers for the "call", and remove this frame,
-		** and any other frames above it, from the nondet stack.
-		*/
-
 		this_frame = MR_saved_curfr(saved_regs);
-
 		MR_saved_succip(saved_regs) = MR_succip_slot(this_frame);
 		MR_saved_curfr(saved_regs) = MR_succfr_slot(this_frame);
 		MR_saved_maxfr(saved_regs) = MR_prevfr_slot(this_frame);
 		MR_trace_event_number = MR_event_num_framevar(this_frame);
+		MR_trace_call_seqno = MR_call_num_framevar(this_frame) - 1;
+		MR_trace_call_depth = MR_call_depth_framevar(this_frame) - 1;
 
 #ifdef	MR_USE_TRAIL
-		if (entry->MR_sle_maybe_trail >= 0) {
+		if (level_layout->MR_sle_maybe_trail >= 0) {
 			Word	ticket_counter;
 			Word	trail_ptr;
 
 			trail_ptr = MR_based_framevar(this_frame,
-					entry->MR_sle_maybe_trail);
+					level_layout->MR_sle_maybe_trail);
 			ticket_counter = MR_based_framevar(this_frame,
-					entry->MR_sle_maybe_trail+1);
+					level_layout->MR_sle_maybe_trail+1);
 			MR_reset_ticket(trail_ptr, MR_retry);
 			MR_discard_tickets_to(ticket_counter);
 		} else {
@@ -524,12 +612,8 @@
 		saved_reg(saved_regs, i) = args[i];
 	}
 
-	if (args != NULL) {
-		free(args);
-	}
-
 	event_info->MR_max_mr_num = max(event_info->MR_max_mr_num, arg_max);
-	*jumpaddr = entry->MR_sle_code_addr;
+	*jumpaddr = level_layout->MR_sle_code_addr;
 
 	/*
 	** Overriding MR_trace_call_seqno etc is not enough, because
@@ -541,13 +625,122 @@
 	event_details->MR_call_depth = MR_trace_call_depth;
 	event_details->MR_event_number = MR_trace_event_number;
 
+	if (args != NULL) {
+		MR_free(args);
+	}
+
+	MR_reset_call_table_array();
+	return MR_RETRY_OK_DIRECT;
+
+report_problem:
+	if (args != NULL) {
+		MR_free(args);
+	}
+
+	MR_abandon_call_table_array();
+	return MR_RETRY_ERROR;
+}
+
+/*
+** This function figures out the state of the stacks (i.e. the values of sp,
+** curfr and maxfr) just after entry to the procedure specified by the given
+** ancestor level, and returns the proc layout for the specified procedure.
+** It also
+**
+** If it finds that it cannot do its job, it returns NULL and sets *problem
+** to point to a string giving the reason for its failure.
+*/
+
+static const MR_Stack_Layout_Entry *
+MR_unwind_stacks_for_retry(const MR_Stack_Layout_Label *top_layout,
+	int ancestor_level, Word **sp_ptr, Word **curfr_ptr, Word **maxfr_ptr,
+	const char **problem)
+{
+	MR_Stack_Walk_Step_Result       result;
+	const MR_Stack_Layout_Entry	*level_layout;
+	const MR_Stack_Layout_Label	*return_label_layout;
+	int				i;
+
+	if (ancestor_level < 0) {
+		*problem = "no such stack frame";
+		return NULL;
+	}
+
+	level_layout = top_layout->MR_sll_entry;
+	*problem = MR_undo_updates_of_maxfr(level_layout,
+			*sp_ptr, *curfr_ptr, maxfr_ptr);
+
+	if (*problem != NULL) {
+		return NULL;
+	}
+
+	MR_maybe_record_call_table(level_layout, *sp_ptr, *curfr_ptr);
+
+	for (i = 0; i < ancestor_level; i++) {
+		result = MR_stack_walk_step(level_layout, &return_label_layout,
+				sp_ptr, curfr_ptr, problem);
+		if (result != STEP_OK) {
+			if (*problem == NULL) {
+				*problem = "not that many ancestors";
+			}
+
+			return NULL;
+		}
+
+		level_layout = return_label_layout->MR_sll_entry;
+		*problem = MR_undo_updates_of_maxfr(level_layout,
+				*sp_ptr, *curfr_ptr, maxfr_ptr);
+
+		if (*problem != NULL) {
 	return NULL;
+		}
+
+		MR_maybe_record_call_table(level_layout, *sp_ptr, *curfr_ptr);
+	}
+
+	return level_layout;
 }
 
+static const char *
+MR_undo_updates_of_maxfr(const MR_Stack_Layout_Entry *level_layout,
+	Word *sp, Word *curfr, Word **maxfr_ptr)
+{
+	if (MR_DETISM_DET_STACK(level_layout->MR_sle_detism)) {
+		/*
+		** The code of a procedure that lives on the det stack
+		** never updates curfr, but may update maxfr by pushing
+		** a temporary nondet frame. If it does so, and the
+		** procedure is traced, the original value of maxfr 
+		** will be saved in a stack slot.
+		*/
+
+		if (! MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(level_layout)) {
+			return "an intervening stack frame "
+				"has no debugging information";
+		} else if (level_layout->MR_sle_maybe_maxfr > 0) {
+			*maxfr_ptr = (Word *) MR_based_stackvar(sp,
+				level_layout->MR_sle_maybe_maxfr);
+			fprintf(stdout, "resetting maxfr to ");
+			MR_print_nondstackptr(stdout, *maxfr_ptr);
+			fprintf(stdout, "\n");
+		} /* else we need do nothing */
+	} else {
+		/*
+		** When we finish setting up the stack frame of a
+		** procedure that lives on the nondet stack,
+		** maxfr == curfr.
+		*/
 
+		*maxfr_ptr = curfr;
+	}
+
+	return NULL;
+}
+
 static Word
 MR_trace_find_input_arg(const MR_Stack_Layout_Label *label, Word *saved_regs,
-	MR_uint_least16_t var_num, bool *succeeded)
+	Word *base_sp, Word *base_curfr, MR_uint_least16_t var_num,
+	bool *succeeded)
 {
 	const MR_Stack_Layout_Vars	*vars;
 	int				i;
@@ -563,17 +756,302 @@
 			if (i < MR_long_desc_var_count(vars)) {
 				return MR_lookup_long_lval_base(
 					MR_long_desc_var_locn(vars, i),
-					saved_regs, MR_saved_sp(saved_regs),
-					MR_saved_curfr(saved_regs), succeeded);
+					saved_regs, base_sp, base_curfr,
+					succeeded);
 			} else {
 				return MR_lookup_short_lval_base(
 					MR_short_desc_var_locn(vars, i),
-					saved_regs, MR_saved_sp(saved_regs),
-				MR_saved_curfr(saved_regs), succeeded);
+					saved_regs, base_sp, base_curfr,
+					succeeded);
 			}
 		}
 	}
 
 	*succeeded = FALSE;
 	return 0;
+}
+
+/*****************************************************************************/
+
+#ifdef	MR_USE_MINIMAL_MODEL
+
+/*
+** MR_check_minimal_model_calls scans the nondet stack region about to be
+** discarded by the retry operation, searching for the stack frames of
+** procedures whose evaluation method is minimal model.
+**
+** In grades that do enable minimal model tabling, redoip hijacking is
+** disabled, so the fact that the redoip slot of a nondet stack frame points
+** to a label within a given procedure means that the frame was created by that
+** procedure.
+**
+** If we ever get here, the redoip slot of the home frame of every model_non
+** procedure compiled with debugging ought to point to a label in its own code,
+** not to a label in the runtime system.
+*/
+
+#define	INIT_RECORD_ARRAY_SIZE		10
+
+typedef	struct {
+	MR_Subgoal	*record_subgoal;
+	MR_Subgoal	*record_leader;
+	bool		found_leader_generator;
+} MR_Minimal_Model_Record;
+
+static MR_Retry_Result
+MR_check_minimal_model_calls(MR_Event_Info *event_info, int ancestor_level,
+	Word *target_maxfr, const char **problem)
+{
+	const MR_Stack_Layout_Label	*label_layout;
+	const MR_Stack_Layout_Entry	*proc_layout;
+	Word				*top_maxfr;
+	Word				*cur_maxfr;
+	Code				*redoip;
+	MR_TrieNode			trienode;
+	MR_Subgoal			*subgoal;
+	MR_Subgoal			*leader;
+	MR_Minimal_Model_Record		*record_ptrs;
+	int				record_ptr_max;
+	int				record_ptr_next;
+	int				frame_size;
+	int				cur_gen;
+	MR_Internal			*label;
+	int				i;
+	bool				any_missing_generators;
+
+	top_maxfr = MR_saved_maxfr(event_info->MR_saved_regs);
+	cur_gen = MR_gen_next - 1;
+
+	for (cur_maxfr = top_maxfr;
+		cur_maxfr > target_maxfr;
+		cur_maxfr = MR_prevfr_slot(cur_maxfr))
+	{
+		frame_size = cur_maxfr - MR_prevfr_slot(cur_maxfr);
+		if (frame_size == MR_NONDET_TEMP_SIZE) {
+			/*
+			** These frames represent auxiliary frames of model_non
+			** procedures. We will traverse the main frame of every
+			** such procedure as well, and we can do everything we
+			** need to do then, so we can ignore these frames.
+			*/
+
+			continue;
+		} else if (frame_size == MR_DET_TEMP_SIZE) {
+			/*
+			** These frames represent auxiliary frames of model_det
+			** or model_semi procedures, which call a model_non
+			** procedure inside a commit. We should queue the
+			** associated commit stack entry for resetting,
+			** but the future of the commit stack is in flux
+			** at the moment (it has some design-level bugs),
+			** so for now we just note the need for future work
+			** here XXX.
+			*/
+
+			continue;
+		}
+
+		/*
+		** The remaining frames represent the main frames of model_non
+		** procedures.
+		*/
+
+		redoip = MR_prevfr_slot(cur_maxfr);
+		label = MR_lookup_internal_by_addr(redoip);
+		if (label == NULL) {
+			*problem = "reached unknown label ";
+			return MR_RETRY_ERROR;
+		}
+
+		if (label->i_layout == NULL) {
+			*problem = "reached label without debugging info";
+			return MR_RETRY_ERROR;
+		}
+
+		label_layout = label->i_layout;
+		proc_layout = label_layout->MR_sll_entry;
+
+		if (! MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(proc_layout)) {
+			*problem = "reached label without debugging info";
+			return MR_RETRY_ERROR;
+		}
+
+		if (proc_layout->MR_sle_eval_method != MR_EVAL_METHOD_MINIMAL)
+		{
+			continue;
+		}
+
+		if (proc_layout->MR_sle_maybe_call_table <= 0) {
+			fatal_error("minimal model procedure "
+					"has no call table slot");
+		}
+
+		trienode = (MR_TrieNode) MR_based_framevar(cur_maxfr, 
+					proc_layout->MR_sle_maybe_call_table);
+		subgoal = trienode->MR_subgoal;
+		if (subgoal->leader != NULL) {
+			leader = subgoal->leader;
+		} else {
+			leader = subgoal;
+		}
+
+		MR_ensure_room_for_next(record_ptr, MR_Minimal_Model_Record,
+			INIT_RECORD_ARRAY_SIZE);
+
+		record_ptrs[record_ptr_next].record_subgoal = subgoal;
+		record_ptrs[record_ptr_next].record_leader = leader;
+		record_ptrs[record_ptr_next].found_leader_generator = FALSE;
+		record_ptr_next++;
+
+		if (cur_maxfr == MR_gen_stack[cur_gen].generator_frame) {
+			for (i = 0; i < record_ptr_next; i++) {
+				if (record_ptrs[i].record_leader == subgoal) {
+					record_ptrs[i].found_leader_generator
+						= TRUE;
+				}
+			}
+
+			cur_gen--;
+		}
+	}
+
+	any_missing_generators = FALSE;
+	for (i = 0; i < record_ptr_next; i++) {
+		if (! record_ptrs[i].found_leader_generator) {
+			any_missing_generators = TRUE;
+		}
+	}
+
+	if (any_missing_generators) {
+		*problem = "retry would interfere with minimal model tabling";
+		return MR_RETRY_ERROR;
+	} else if (record_ptr_next > 0) {
+		if (event_info->MR_trace_port == MR_PORT_EXCEPTION
+		&& ancestor_level == 0)
+		{
+			*problem = "cannot retry minimal model procedure "
+				"from the exception port";
+			return MR_RETRY_ERROR;
+		}
+
+		label_layout = event_info->MR_event_sll;
+		proc_layout = label_layout->MR_sll_entry;
+
+		if (proc_layout->MR_sle_eval_method == MR_EVAL_METHOD_MINIMAL) {
+			return MR_RETRY_OK_FAIL_FIRST;
+		} else {
+			return MR_RETRY_OK_FINISH_FIRST;
+		}
+	} else {
+		return MR_RETRY_OK_DIRECT;
+	}
+}
+
+#endif	/* MR_USE_MINIMAL_MODEL */
+
+/*****************************************************************************/
+
+/*
+** The rest of this file implements the mechanism that the retry command uses
+** to reset the call tables of any calls being retried over.
+**
+** Each execution of MR_trace_retry is required to make the following
+** sequence of calls on this submodule:
+**
+**	one call to MR_init_call_table_array
+**	zero or more calls to MR_maybe_record_call_table
+**	one call to either
+**		MR_reset_call_table_array (if the direct retry is successful)
+**		MR_abandon_call_table_array (if it is not)
+*/
+
+static	MR_TrieNode	*MR_call_table_ptrs;
+static	int		MR_call_table_ptr_max;
+static	int		MR_call_table_ptr_next;
+
+#define	INIT_CALL_TABLE_ARRAY_SIZE	10
+
+static void
+MR_init_call_table_array(void)
+{
+	MR_call_table_ptr_max = 0;
+}
+
+static void
+MR_maybe_record_call_table(const MR_Stack_Layout_Entry *level_layout,
+	Word *sp, Word *curfr)
+{
+	MR_TrieNode	call_table;
+
+	if (! MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(level_layout)) {
+		/*
+		** The exec trace seems to have disappeared since the call
+		** to MR_undo_updates_of_maxfr ...
+		*/
+
+		fatal_error("proc layout without exec trace "
+				"in MR_maybe_record_call_table");
+	}
+
+	switch ((MR_EvalMethod) level_layout->MR_sle_eval_method) {
+
+	case MR_EVAL_METHOD_NORMAL:
+		/* nothing to do */
+		return;
+
+	case MR_EVAL_METHOD_MEMO:
+	case MR_EVAL_METHOD_LOOP_CHECK:
+		if (MR_DETISM_DET_STACK(level_layout->MR_sle_detism)) {
+			call_table = (MR_TrieNode) MR_based_stackvar(sp, 
+				level_layout->MR_sle_maybe_call_table);
+		} else {
+			call_table = (MR_TrieNode) MR_based_framevar(curfr, 
+				level_layout->MR_sle_maybe_call_table);
+		}
+
+		if (call_table != NULL) {
+			MR_ensure_room_for_next(MR_call_table_ptr, MR_TrieNode,
+				INIT_CALL_TABLE_ARRAY_SIZE);
+
+			MR_call_table_ptrs[MR_call_table_ptr_next] =
+				call_table;
+			MR_call_table_ptr_next++;
+		}
+
+		return;
+
+	case MR_EVAL_METHOD_MINIMAL:
+		/*
+		** We want to process all the minimal model calls whose
+		** stack frames are in the part of the nondet stack to be
+		** removed by the retry operation, not just those which are
+		** direct ancestors of the current call. Such calls are
+		** therefore processed in MR_check_minimal_model_calls,
+		** not here.
+		*/
+
+		return;
+	}
+
+	fatal_error("unknown evaluation method in MR_maybe_record_call_table");
+}
+
+static void
+MR_reset_call_table_array(void)
+{
+	int	i;
+
+	for (i = 0; i < MR_call_table_ptr_next; i++) {
+		MR_call_table_ptrs[i]->MR_integer = 0;
+	}
+
+	MR_abandon_call_table_array();
+}
+
+static void
+MR_abandon_call_table_array(void)
+{
+	if (MR_call_table_ptrs != NULL) {
+		MR_free(MR_call_table_ptrs);
+	}
 }
Index: trace/mercury_trace.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace.h,v
retrieving revision 1.12
diff -u -b -r1.12 mercury_trace.h
--- trace/mercury_trace.h	1999/12/14 04:54:38	1.12
+++ trace/mercury_trace.h	2000/01/15 04:45:47
@@ -1,5 +1,5 @@
 /*
-** Copyright (C) 1997-1999 The University of Melbourne.
+** Copyright (C) 1997-2000 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.
 */
@@ -45,16 +45,74 @@
 */
 
 typedef struct MR_Event_Details_Struct {
-	int			MR_call_seqno;
-	int			MR_call_depth;
-	int			MR_event_number;
+	Unsigned			MR_event_number;
+	Unsigned			MR_call_seqno;
+	Unsigned			MR_call_depth;
 } MR_Event_Details;
 
-/* The initial size of arrays of argument values. */
-#define	MR_INIT_ARG_COUNT	20
+/*
+** The above declarations are part of the interface between MR_trace_real
+** and the internal and external debuggers. Even though MR_trace_real is
+** defined in mercury_trace.c, its prototype is not here. Instead, it is
+** in runtime/mercury_init.h. This is necessary because the address of
+** MR_trace_real may be taken in automatically generated <main>_init.c files,
+** and we do not want to include mercury_trace.h in such files; we don't want
+** them to refer to the trace directory at all unless debugging is enabled.
+*/
 
-extern	const char *MR_trace_retry(MR_Event_Info *event_info,
-			MR_Event_Details *event_details, Code **jumpaddr);
+/*
+** Ideally, MR_trace_retry works by resetting the state of the stacks and
+** registers to the state appropriate for the call to the selected ancestor,
+** setting *jumpaddr to point to the start of the code for the selected
+** ancestor, and returning MR_RETRY_OK_DIRECT.
+**
+** If resetting the stacks requires discarding the stack frame of a procedure
+** whose evaluation method is memo or loopcheck, we must also reset the call
+** table entry for that particular call to uninitialized. There are two reasons
+** for this. The first is that the call table entry was uninitialized at the
+** time of the first call, so if the retried call is to what the original call
+** did, it must find the call table entry in the same state. The second reason
+** is that if we did not reset the call table entry, then the retried call
+** would find the "call active" marker left by the original call, and since
+** this normally indicates an infinite loop, it will generate a runtime abort.
+**
+** Unfortunately, resetting the call table entry to uninitialized does not work
+** in general for procedures whose evaluation method is minimal model tabling.
+** In such procedures, a subgoal can be a consumer as well as a generator,
+** and control passes between consumers and generators in a complex fashion.
+** There is no safe way to reset the state of such a system, except to wait
+** for normal forward execution to execute the completion operation on an
+** SCC of mutually dependent subgoals.
+**
+** If the stack segments between the current call and the call to be retried
+** contain one or more such complete SCCs, then MR_trace_retry will return
+** either MR_RETRY_OK_FINISH_FIRST or MR_RETRY_OK_FAIL_FIRST. The first
+** indicates that the `retry' command should be executed only after a `finish'
+** command on the selected call has made the state of the SCC quiescent.
+** However, if the selected call is itself a generator, then reaching one of
+** its exit ports is not enough to make its SCC quiescent; for that, one must
+** wait for its failure. This is why in such cases, MR_trace_retry will ask
+** for the `retry' command to be executed only after a `fail' command.
+** 
+** If the fail command reaches an exception port on the selected call instead
+** of the fail port, then the SCC cannot be made quiescent, and MR_trace_retry
+** will return MR_RETRY_ERROR, putting a description of the error into
+** *problem. It will also do this for other, more prosaic problems, such as
+** when it finds that some of the stack frames it looks at lack debugging
+** information.
+*/
+
+typedef	enum {
+	MR_RETRY_OK_DIRECT,
+	MR_RETRY_OK_FINISH_FIRST,
+	MR_RETRY_OK_FAIL_FIRST,
+	MR_RETRY_ERROR
+} MR_Retry_Result;
+
+extern	MR_Retry_Result	MR_trace_retry(MR_Event_Info *event_info,
+				MR_Event_Details *event_details,
+				int ancestor_level, const char **problem,
+				Code **jumpaddr);
 
 /*
 ** MR_trace_cmd says what mode the tracer is in, i.e. how events should be
@@ -67,6 +125,10 @@
 ** event that specifies the procedure invocation whose call number is in
 ** MR_trace_stop_seqno and whose port is EXIT or FAIL or EXCEPTION.
 **
+** If MR_trace_cmd == MR_CMD_FAIL, the event handler will stop at the next
+** event that specifies the procedure invocation whose call number is in
+** MR_trace_stop_seqno and whose port is FAIL or EXCEPTION.
+**
 ** If MR_trace_cmd == MR_CMD_RESUME_FORWARD, the event handler will stop at
 ** the next event of any call whose port is *not* REDO or FAIL or EXCEPTION.
 **
@@ -89,6 +151,7 @@
 typedef enum {
 	MR_CMD_GOTO,
 	MR_CMD_FINISH,
+	MR_CMD_FAIL,
 	MR_CMD_RESUME_FORWARD,
 	MR_CMD_RETURN,
 	MR_CMD_MIN_DEPTH,
Index: trace/mercury_trace_declarative.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_declarative.c,v
retrieving revision 1.14
diff -u -b -r1.14 mercury_trace_declarative.c
--- trace/mercury_trace_declarative.c	2000/01/03 02:23:03	1.14
+++ trace/mercury_trace_declarative.c	2000/01/15 04:45:48
@@ -811,6 +811,7 @@
 		MR_Event_Info *event_info, MR_Event_Details *event_details,
 		Code **jumpaddr)
 {
+	MR_Retry_Result		result;
 	MR_Stack_Layout_Entry 	*entry;
 	int			decl_slot;
 	const char		*message;
@@ -827,8 +828,9 @@
 		return FALSE;
 	}
 
-	message = MR_trace_retry(event_info, event_details, jumpaddr);
-	if (message != NULL) {
+	result = MR_trace_retry(event_info, event_details, 0,
+			&message, jumpaddr);
+	if (result != MR_RETRY_OK_DIRECT) {
 		return FALSE;
 	}
 
Index: trace/mercury_trace_external.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_external.c,v
retrieving revision 1.34
diff -u -b -r1.34 mercury_trace_external.c
--- trace/mercury_trace_external.c	1999/12/20 11:34:17	1.34
+++ trace/mercury_trace_external.c	2000/01/15 04:45:48
@@ -498,6 +498,7 @@
 	Integer		modules_list_length;
 	Word		modules_list;
 	static String	MR_object_file_name;
+	MR_Retry_Result	retry_result;
 
 	MR_trace_enabled = FALSE;
 
@@ -616,9 +617,9 @@
 					fprintf(stderr, "\nMercury runtime: "
 						"REQUEST_RETRY\n");
 				}
-				message = MR_trace_retry(event_info, 
-					&event_details, &jumpaddr);
-				if (message == NULL) {
+				retry_result = MR_trace_retry(event_info, 
+					&event_details, 0, &message, &jumpaddr);
+				if (retry_result == MR_RETRY_OK_DIRECT) {
 					MR_send_message_to_socket("ok");
 					cmd->MR_trace_cmd = MR_CMD_GOTO;
 					cmd->MR_trace_stop_event = 
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.62
diff -u -b -r1.62 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	2000/01/03 08:53:15	1.62
+++ trace/mercury_trace_internal.c	2000/01/15 04:45:48
@@ -617,6 +617,55 @@
 			cmd->MR_trace_stop_depth = stop_depth;
 			return STOP_INTERACTING;
 		}
+	} else if (streq(words[0], "fail")) {
+		MR_Determinism	detism = event_info->MR_event_sll->
+					MR_sll_entry->MR_sle_detism;
+		Unsigned	depth = event_info->MR_call_depth;
+		int		stop_depth;
+		int		n;
+
+		cmd->MR_trace_strict = TRUE;
+		cmd->MR_trace_print_level = MR_default_print_level;
+		if (! MR_trace_options_strict_print(cmd, &words, &word_count,
+				"forward", "fail"))
+		{
+			; /* the usage message has already been printed */
+			return KEEP_INTERACTING;
+		} else if (word_count == 2 && MR_trace_is_number(words[1], &n))
+		{
+			stop_depth = depth - n;
+		} else if (word_count == 1) {
+			stop_depth = depth;
+		} else {
+			MR_trace_usage("forward", "fail");
+			return KEEP_INTERACTING;
+		}
+
+		if (MR_DETISM_DET_STACK(detism)) {
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err,
+				"mdb: cannot continue until failure: "
+				"selected procedure has determinism %s.\n",
+				MR_detism_names[detism]);
+			return KEEP_INTERACTING;
+		}
+
+		if (depth == stop_depth &&
+			event_info->MR_trace_port == MR_PORT_FAIL)
+		{
+			MR_trace_do_noop();
+		} else if (depth == stop_depth &&
+			event_info->MR_trace_port == MR_PORT_EXCEPTION)
+		{
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err,
+				"mdb: cannot continue until failure: "
+				"the call has raised an exception.\n");
+		} else {
+			cmd->MR_trace_cmd = MR_CMD_FAIL;
+			cmd->MR_trace_stop_depth = stop_depth;
+			return STOP_INTERACTING;
+		}
 	} else if (streq(words[0], "return")) {
 		cmd->MR_trace_strict = TRUE;
 		cmd->MR_trace_print_level = MR_default_print_level;
@@ -720,46 +769,60 @@
 		}
 	} else if (streq(words[0], "retry")) {
 		int		n;
-		int		stop_depth;
-		const char   	*message;
-		Unsigned	depth = event_info->MR_call_depth;
-		MR_Trace_Port	port = event_info->MR_trace_port;
+		int		ancestor_level;
+		const char	*problem;
+		MR_Retry_Result	result;
 
 		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
-			stop_depth = depth - n;
+			ancestor_level = n;
 		} else if (word_count == 1) {
-			stop_depth = depth;
+			ancestor_level = 0;
 		} else {
 			MR_trace_usage("backward", "retry");
 			return KEEP_INTERACTING;
 		}
 
-		if (stop_depth == depth && MR_port_is_final(port)) {
-			message = MR_trace_retry(event_info, event_details,
-					jumpaddr);
-			if (message != NULL) {
-				fflush(MR_mdb_out);
-				fprintf(MR_mdb_err, "%s\n", message);
-				return KEEP_INTERACTING;
-			}
+		result = MR_trace_retry(event_info, event_details,
+				ancestor_level, &problem, jumpaddr);
+		switch (result) {
+
+		case MR_RETRY_OK_DIRECT:
 			cmd->MR_trace_cmd = MR_CMD_GOTO;
 			cmd->MR_trace_stop_event = MR_trace_event_number + 1;
 			cmd->MR_trace_strict = FALSE;
 			cmd->MR_trace_print_level = MR_default_print_level;
 			return STOP_INTERACTING;
-		} else if (stop_depth == depth && MR_port_is_entry(port)) {
-			MR_trace_do_noop();
-		} else {
-			/* Finish the call to be retried. */
+
+		case MR_RETRY_OK_FINISH_FIRST:
 			cmd->MR_trace_cmd = MR_CMD_FINISH;
-			cmd->MR_trace_stop_depth = stop_depth;
+			cmd->MR_trace_stop_depth = event_info->MR_call_depth
+							- ancestor_level;
 			cmd->MR_trace_strict = TRUE;
 			cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
 
 			/* Arrange to retry the call once it is finished. */
 			MR_insert_line_at_head("retry");
 			return STOP_INTERACTING;
+
+		case MR_RETRY_OK_FAIL_FIRST:
+			cmd->MR_trace_cmd = MR_CMD_FAIL;
+			cmd->MR_trace_stop_depth = event_info->MR_call_depth
+							- ancestor_level;
+			cmd->MR_trace_strict = TRUE;
+			cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
+
+			/* Arrange to retry the call once it is finished. */
+			MR_insert_line_at_head("retry");
+			return STOP_INTERACTING;
+
+		case MR_RETRY_ERROR:
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err, "%s\n", problem);
+			return KEEP_INTERACTING;
 		}
+
+		fatal_error("unrecognized retry result");
+
 	} else if (streq(words[0], "level")) {
 		int	n;
 		bool	detailed;
cvs diff: Diffing trial
cvs diff: Diffing util
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list