[m-dev.] for review: retry across I/O
Zoltan Somogyi
zs at cs.mu.OZ.AU
Mon Dec 4 16:56:36 AEDT 2000
On 08-Nov-2000, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 06-Nov-2000, Zoltan Somogyi <zs at cs.mu.OZ.AU> wrote:
> > eval_method_requires_ground_args(eval_normal) = no.
> > eval_method_requires_ground_args(eval_loop_check) = yes.
> > +eval_method_requires_ground_args(eval_table_io) = yes.
> > eval_method_requires_ground_args(eval_memo) = yes.
> > eval_method_requires_ground_args(eval_minimal) = yes.
>
> Hmm, the error message that you will get for violations of this will
> be from report_eval_method_requires_ground_args in modes.m, which will
> output the following message:
>
> foo.m:123: Sorry, not implemented: `pragma table_io'
> foo.m:123: declaration not allowed for procedure with
> foo.m:123: partially instantiated modes.
>
> This is misleading since there's no `pragma table_io' declaration.
Eval_method_requires_ground_args should only be called before the tabling
phase, so I made it call error if its argument is eval_table_io.
> > + if (MR_DETISM_DET_STACK(level_layout->MR_sle_detism)) {
> > + saved_io_counter = MR_based_stackvar(base_sp,
> > + level_layout->MR_sle_maybe_io_seq);
> > + } else {
> > + saved_io_counter = MR_based_framevar(base_curfr,
> > + level_layout->MR_sle_maybe_io_seq);
> > + }
>
> It would be cleaner if some of that was abstracted out into a macro
> (or function), i.e.
>
> #define MR_based_slot(layout, base_sp, base_curfr, slot) \
> ( MR_DETISM_DET_STACK((layout)->MR_sle_detism) ? \
> MR_based_stackvar((base_sp), (slot)) \
> : \
> MR_based_framevar((base_curfr), (slot)) \
> ) \
I don't want to do this. With the original, verbose version, there is a good
chance that either the author or the reviewer will catch passing base_sp to
MR_based_framevar or vice versa. With the macro, the chance that someone will
catch passing base_sp and base_curfr in the wrong order is much smaller,
and the resulting bug would be tough to track down. Given that the macro
only saves a few lines of code, the tradeoff is not worth it.
I did make all the other suggestions. After the new log message, an interdiff
follows. Since this had some rejected hunks, I will post the whole new diff
in the next message.
Add tabling of I/O actions for the debugger.
compiler/options.m:
Add a new option, --trace-table-io, that enables the tabling of I/O
actions, and another, --trace-table-io-states, that governs whether the
tabling includes the I/O state variables themselves. (You want to table
these variables iff they contain meaningful information that is not
stored in global variables.) These options are for developers only
for now.
compiler/modules.m:
Implicitly import table_builtin if --trace-table-io is specified.
compiler/prog_data.m:
Add eval_table_io as a new eval method.
compiler/hlds_pred.m:
Add a mechanism for checking whether a predicate has an input/output
pair of io__state args.
Extend the tables indexed by eval_method to handle eval_table_io.
compiler/hlds_out.m:
Print the eval method in HLDS dumps.
compiler/table_gen.m:
If a procedure has a pair of I/O state args and is defined using pragma
C code that has the tabled_for_io marker, and --trace-table-io is
specified, then perform I/O tabling on it and mark it as tabled.
compiler/notes/compiler_design.m:
Document that table_gen.m can now change the evaluation methods of
procedures (to eval_table_io).
compiler/stack_layout.m:
runtime/mercury_stack_layout.h:
Add an extra field to proc layouts. If debugging is enabled and a
procedure has I/O state arguments, this field gives the number of the
stack slot which will be filled with the I/O action counter at the
time of the call, so that on retry the debugger can reset the I/O
action counter to this value.
compiler/trace.m:
Add code to reserve and fill this stack slot.
Make the order of fields in the trace_slots structure match the order
in proc layouts.
compiler/code_info.m:
compiler/live_vars.m:
Pass a module_info to trace__setup and trace__reserved_slots.
library/io.m:
Mark the I/O primitives (i.e. procedures that are defined by pragma C
code and do I/O) with the tabled_for_io feature. (See the discussion
of I/O primitives in compiler/table_gen.m.)
Standardize the formatting of predicates defined by pragma C codes.
library/table_builtin.m:
Define the predicates that perform I/O tabling, to which calls are
inserted in I/O tabled predicates. These depend on knowing what the
maximum MR_Unsigned value is.
library/table_builtin.m:
runtime/mercury_tabling_macros.h:
Table nodes implementing a simple kind of trie, which can also be
viewed as a hash table with the hash function hash(n) = hash - start
were already supported by mercury_tabling.c. They are used to
implement I/O tabling, since I/O the tabled action numbers form a
contiguous sequence. Now allow that functionality to be accessed
from the library through macros.
runtime/mercury_trace_base.[ch]:
Add the global variables required by I/O tabling.
trace/mercury_trace.c:
Implement retry across I/O by resetting the I/O counter to the value
it had on entry to the retried call.
trace/mercury_trace_internal.c:
Add commands to start and stop I/O tabling. For now, they are for use
by developers only and are undocumented; I expect they will change
significantly before being let loose on users.
tests/debugger/tabled_read.{m,inp,exp,data}:
A new test case to check retry across tabled I/O.
tests/debugger/Mmakefile:
Enable the new test case.
--- configure.in 2000/10/30 10:53:19
+++ configure.in 2000/10/20 10:23:45 1.230
@@ -844,81 +844,10 @@
if test "$mercury_cv_word_type" = int; then
AC_DEFINE_UNQUOTED(MR_INTEGER_LENGTH_MODIFIER, "")
- AC_DEFINE_UNQUOTED(MR_INTEGER_MAX, INT_MAX)
- AC_DEFINE_UNQUOTED(MR_UNSIGNED_MAX, UINT_MAX)
elif test "$mercury_cv_word_type" = long; then
AC_DEFINE_UNQUOTED(MR_INTEGER_LENGTH_MODIFIER, "l")
- AC_DEFINE_UNQUOTED(MR_INTEGER_MAX, LONG_MAX)
- AC_DEFINE_UNQUOTED(MR_UNSIGNED_MAX, ULONG_MAX)
elif test "$mercury_cv_word_type" = "long long"; then
AC_DEFINE_UNQUOTED(MR_INTEGER_LENGTH_MODIFIER, "ll")
- AC_TRY_RUN([
- #include <stdio.h>
-
- extern void signed_size(FILE *fp);
- extern void unsigned_size(FILE *fp);
-
- int main(void)
- {
- FILE *fp;
-
- fp = fopen("conftest.intmax", "w");
- if (fp == NULL)
- return 1;
- signed_size(fp);
-
- fp = fopen("conftest.uintmax", "w");
- if (fp == NULL)
- return 1;
- unsigned_size(fp);
-
- return 0;
- }
-
- void signed_size(FILE *fp)
- {
- long long cur, prev;
-
- cur = 1;
- prev = 0;
-
- while (cur > prev) {
- prev = cur;
- cur = (cur << 1) + 1;
- }
-
- fprintf(fp, "%lld\n", prev);
- }
-
- void unsigned_size(FILE *fp)
- {
- long long unsigned cur, prev;
-
- cur = 1;
- prev = 0;
-
- while (cur > prev) {
- prev = cur;
- cur = (cur << 1) + 1;
- }
-
- fprintf(fp, "%llu\n", prev);
- }
- }],
- [mercury_cv_int_max=`cat conftest.intmax` ;
- mercury_cv_uint_max=`cat conftest.uintmax`],
- [mercury_cv_int_max=unknown ; mercury_cv_uint_max=unknown],
- [mercury_cv_int_max=unknown ; mercury_cv_uint_max=unknown])
- if test "$mercury_cv_int_max" = "unknown"; then
- AC_MSG_ERROR("Cannot determine the maximum MR_Integer value.")
- else
- AC_DEFINE_UNQUOTED(MR_INTEGER_MAX, LONG_MAX)
- fi
- if test "$mercury_cv_uint_max" = "unknown"; then
- AC_MSG_ERROR("Cannot determine the maximum MR_Unsigned value.")
- else
- AC_DEFINE_UNQUOTED(MR_UNSIGNED_MAX, ULONG_MAX)
- fi
else
AC_MSG_ERROR("Cannot determine the length modifier for the MR_Integer type.")
fi
--- compiler/hlds_out.m
+++ compiler/hlds_out.m
@@ -294,2 +294 @@
-hlds_out__cons_id_to_string(tabling_pointer_const(_, _),
- "<tabling_pointer>").
+hlds_out__cons_id_to_string(tabling_pointer_const(_, _), "<tabling_pointer>").
@@ -308 +307,2 @@
-hlds_out__cons_id_to_string(tabling_pointer_const(_, _), "<tabling_pointer>").
+hlds_out__cons_id_to_string(tabling_pointer_const(_, _),
+ "<tabling_pointer>").
@@ -2876 +2875,0 @@
- { proc_info_eval_method(Proc, EvalMethod) },
@@ -2891,0 +2891 @@
+ { proc_info_eval_method(Proc, EvalMethod) },
@@ -2925,4 +2924,0 @@
- io__write_string("% eval method: "),
- hlds_out__write_eval_method(EvalMethod),
- io__write_string("\n"),
-
@@ -2943,0 +2940,8 @@
+ ( { EvalMethod = eval_normal } ->
+ []
+ ;
+ io__write_string("% eval method: "),
+ hlds_out__write_eval_method(EvalMethod),
+ io__write_string("\n")
+ ),
+
@@ -3063,0 +3068,8 @@
+:- pred hlds_out__write_indent(int, io__state, io__state).
+:- mode hlds_out__write_indent(in, di, uo) is det.
+
+
+ io__write_string("can_fail").
+hlds_out__write_can_fail(cannot_fail) -->
+ io__write_string("cannot_fail").
+
@@ -3074,8 +3085,0 @@
-
-:- pred hlds_out__write_indent(int, io__state, io__state).
-:- mode hlds_out__write_indent(in, di, uo) is det.
-
-
- io__write_string("can_fail").
-hlds_out__write_can_fail(cannot_fail) -->
- io__write_string("cannot_fail").
--- compiler/hlds_pred.m
+++ compiler/hlds_pred.m
@@ -1508,12 +1507,0 @@
- % If the procedure has a pair of io:state arguments, return the index
- % of those arguments. The first output argument gives the index of the
- % input state, the second the output state.
- %
- % Note that the automatically constructed unify, index and compare
- % procedures for the io:state type are not counted as having io:state
- % args, since they do not fall into the scheme of one input and one
- % output arg. Since they should never be called, this should not
- % matter.
-:- pred proc_info_has_io_state_args(module_info::in, proc_info::in,
- int::out, int::out) is semidet.
-
@@ -1528,0 +1517,15 @@
+ % If the procedure has a input/output pair of io__state arguments,
+ % return the positions of those arguments in the argument list.
+ % The positions are given as argument numbers, with the first argument
+ % in proc_info_headvars being position 1, and so on. The first output
+ % argument gives the position of the input state, the second the
+ % position of the output state.
+ %
+ % Note that the automatically constructed unify, index and compare
+ % procedures for the io:state type are not counted as having io:state
+ % args, since they do not fall into the scheme of one input and one
+ % output arg. Since they should never be called, this should not
+ % matter.
+:- pred proc_info_has_io_state_pair(module_info::in, proc_info::in,
+ int::out, int::out) is semidet.
+
@@ -2008 +2011 @@
-proc_info_has_io_state_args(ModuleInfo, ProcInfo, InArgNum, OutArgNum) :-
+proc_info_has_io_state_pair(ModuleInfo, ProcInfo, InArgNum, OutArgNum) :-
@@ -2014 +2017 @@
- proc_info_has_io_state_args_2(HeadVarsModes, ModuleInfo, VarTypes,
+ proc_info_has_io_state_pair_2(HeadVarsModes, ModuleInfo, VarTypes,
@@ -2019,2 +2021,0 @@
- ; MaybeIn = no, MaybeOut = no ->
- fail
@@ -2022,4 +2022,0 @@
- % We must be processing the automatically generated index
- % procedure for the io_state type. Since this predicate
- % should never be called, any transformation meant for
- % procedures with io:states would be inappropriate.
@@ -2029 +2026 @@
-:- pred proc_info_has_io_state_args_2(assoc_list(prog_var, mode)::in,
+:- pred proc_info_has_io_state_pair_2(assoc_list(prog_var, mode)::in,
@@ -2032 +2029 @@
- maybe(int)::out, maybe(int)::out) is det.
+ maybe(int)::out, maybe(int)::out) is semidet.
@@ -2034 +2031 @@
-proc_info_has_io_state_args_2([], _, _, _,
+proc_info_has_io_state_pair_2([], _, _, _,
@@ -2036 +2033 @@
-proc_info_has_io_state_args_2([Var - Mode | VarModes], ModuleInfo, VarTypes,
+proc_info_has_io_state_pair_2([Var - Mode | VarModes], ModuleInfo, VarTypes,
@@ -2040,5 +2037 @@
- type_to_type_id(VarType, TypeCtor, []),
- type_util__type_id_module(ModuleInfo, TypeCtor,
- unqualified("io")),
- type_util__type_id_name(ModuleInfo, TypeCtor, "state"),
- type_util__type_id_arity(ModuleInfo, TypeCtor, 0)
+ type_util__type_is_io_state(VarType)
@@ -2047 +2040,2 @@
- ( MaybeIn0 = no ->
+ (
+ MaybeIn0 = no,
@@ -2051 +2045,3 @@
- % We must be processing the automatically
+ MaybeIn0 = yes(_),
+ % Procedures with two input arguments
+ % of type io__state (e.g. the automatically
@@ -2053,7 +2049,4 @@
- % for the io_state type. Since these predicates
- % should never be called, any transformation
- % meant for procedures with io:states would
- % be inappropriate. We therefore effectively
- % forget both io:state arguments.
- MaybeIn1 = no,
- MaybeOut1 = MaybeOut0
+ % for the io__state type) do not fall into
+ % the one input/one output pattern we are
+ % looking for.
+ fail
@@ -2062,4 +2055,11 @@
- require(unify(MaybeOut0, no),
- "proc_info_has_io_state_args_2: two io:state outputs"),
- MaybeOut1 = yes(ArgNum),
- MaybeIn1 = MaybeIn0
+ (
+ MaybeOut0 = no,
+ MaybeOut1 = yes(ArgNum),
+ MaybeIn1 = MaybeIn0
+ ;
+ MaybeOut0 = yes(_),
+ % Procedures with two output arguments of
+ % type io__state do not fall into the one
+ % input/one output pattern we are looking for.
+ fail
+ )
@@ -2067 +2067 @@
- error("proc_info_has_io_state_args_2: bad io:state mode")
+ fail
@@ -2073 +2073 @@
- proc_info_has_io_state_args_2(VarModes, ModuleInfo, VarTypes,
+ proc_info_has_io_state_pair_2(VarModes, ModuleInfo, VarTypes,
@@ -2359 +2359 @@
-:- mode valid_code_model_for_eval_method(in, out) is multi.
+:- mode valid_code_model_for_eval_method(in, out) is multidet.
@@ -2401 +2400,0 @@
-valid_determinism_for_eval_method(eval_memo, _).
@@ -2402,0 +2402,3 @@
+valid_determinism_for_eval_method(eval_table_io, _) :-
+ error("valid_determinism_for_eval_method called after tabling phase").
+valid_determinism_for_eval_method(eval_memo, _).
@@ -2407 +2408,0 @@
-eval_method_to_string(eval_memo, "memo").
@@ -2408,0 +2410,2 @@
+eval_method_to_string(eval_table_io, "table_io").
+eval_method_to_string(eval_memo, "memo").
@@ -2412,0 +2416 @@
+eval_method_needs_stratification(eval_table_io) = no.
@@ -2417,0 +2422 @@
+eval_method_has_per_proc_tabling_pointer(eval_table_io) = no.
@@ -2422,0 +2428 @@
+eval_method_requires_tabling_transform(eval_table_io) = yes.
@@ -2427,0 +2434 @@
+eval_method_requires_ground_args(eval_table_io) = yes.
@@ -2432,0 +2440 @@
+eval_method_destroys_uniqueness(eval_table_io) = no.
@@ -2437,0 +2446 @@
+eval_method_change_determinism(eval_table_io, Detism, Detism).
--- compiler/live_vars.m
+++ compiler/live_vars.m
@@ -67 +67 @@
- trace__reserved_slots(ModuleInfo, ProcInfo1, Globals, NumReservedSlots,
+ trace__reserved_slots(ProcInfo1, Globals, NumReservedSlots,
@@ -82 +82 @@
- trace__reserved_slots(ProcInfo1, Globals, NumReservedSlots,
+ trace__reserved_slots(ModuleInfo, ProcInfo1, Globals, NumReservedSlots,
--- compiler/options.m
+++ compiler/options.m
@@ -491,2 +490,0 @@
- trace_table_io - bool(no),
- trace_table_io_states - bool(no),
@@ -504,0 +503,2 @@
+ trace_table_io - bool(no),
+ trace_table_io_states - bool(no),
@@ -882,2 +881,0 @@
-long_option("trace-table-io", trace_table_io).
-long_option("trace-table-io-states", trace_table_io_states).
@@ -902,0 +901,2 @@
+long_option("trace-table-io", trace_table_io).
+long_option("trace-table-io-states", trace_table_io_states).
@@ -1687,3 +1686,0 @@
- "--trace-table-io",
- "\tEnable the tabling of I/O actions, to allow the debugger",
- "\tto execute retry commands across I/O actions.",
@@ -1713,0 +1711,7 @@
+% "--trace-table-io",
+% "\tEnable the tabling of I/O actions, to allow the debugger",
+% "\tto execute retry commands across I/O actions.",
+% "--trace-table-io-states",
+% "\tWhen tabling I/O actions, table the io__state arguments",
+% "\ttogether with the others. This should be required iff",
+% "\tvalues of type io__state actually contain information.",
--- compiler/stack_layout.m
+++ compiler/stack_layout.m
@@ -430 +430,2 @@
- incr_hp_atomic(tmp, (ArenaSize + sizeof(MR_Word)) / sizeof(MR_Word));
+ MR_incr_hp_atomic(tmp,
+ (ArenaSize + sizeof(MR_Word)) / sizeof(MR_Word));
--- compiler/table_gen.m
+++ compiler/table_gen.m
@@ -157,2 +157,3 @@
-% Example of transformation for tabling I/O, for I/O primitives that have
-% tabled_for_io:
+% Example of transformation for tabling I/O, for I/O primitives (i.e.
+% predicates defined by pragma c_code that take an input/output pair of
+% io_state arguments) that have the tabled_for_io feature:
@@ -181 +182 @@
-% impure table_restore_any_ans(T, 1, S)
+% table_io_copy_io_state(S0, S)
@@ -189,3 +190,2 @@
-% impure table_io_create_ans_block(T, 2, AB),
-% impure table_save_string_ans(AB, 0, B)
-% impure table_save_any_ans(AB, 1, S)
+% impure table_io_create_ans_block(T, 1, AnsBl),
+% impure table_save_string_ans(AnsBl, 0, B)
@@ -199,5 +199,21 @@
-% For I/O primitives that have not_tabled_for_io, we should require that they
-% do not do any I/O in their own code, meaning that all their I/O is inside
-% the Mercury code they call. We can then leave such primitives untransformed;
-% the I/O primitives called from the inner Mercury engine will do the right
-% thing.
+% Note that copying the I/O state works only because variables of type
+% io__state don't actually contain any information; the information is actually
+% stored in global variables. However, if this ever changes, the transformation
+% can be fixed simply by changing the value of --trace-table-io-states to yes,
+% which will cause such values to be tabled along with the other output
+% arguments.
+%
+% For I/O primitives that do not have tabled_for_io, we should require that
+% they do not do any I/O in their own code, meaning that all their I/O is
+% inside any Mercury code they call. We can then leave such primitives
+% untransformed; the I/O primitives called from the inner Mercury engine
+% will do the right thing. For now, this requirement is not enforced,
+% which means that enabling I/O tabling (with --trace-table-io) does not
+% guarantee that *all* I/O actions are tabled. This can cause inconsistent
+% behavior after retry commands in mdb. This is the reason why retry across
+% I/O is experimental for now.
+%
+% The reason why we require I/O primitives to be marked manually by a
+% programmer with the tabled_for_io feature is to get the programmer to make
+% sure that the primitive meets the requirement. Unfortunately, this cannot be
+% automated, since automation would require analysis of arbitrary C code.
@@ -277 +293 @@
- proc_info_has_io_state_args(Module0, ProcInfo0,
+ proc_info_has_io_state_pair(Module0, ProcInfo0,
@@ -278,0 +295 @@
+ proc_info_interface_code_model(ProcInfo0, model_det),
@@ -282 +299 @@
- SubGoal = pragma_foreign_code(_, Attrs, _,_,_,_,_,_)
+ SubGoal = pragma_foreign_code(Attrs, _,_,_,_,_,_)
@@ -316,2 +332,0 @@
- require(unify(CodeModel, model_det),
- "tabled io proc not det"),
@@ -361,0 +377 @@
+
@@ -402 +418 @@
- list__filter(table_gen__var_is_io_state(Module, VarTypes0),
+ list__filter(table_gen__var_is_io_state(VarTypes0),
@@ -431 +447 @@
- list__filter(table_gen__var_is_io_state(Module, VarTypes), InputVars,
+ list__filter(table_gen__var_is_io_state(VarTypes), InputVars,
@@ -444,0 +461,3 @@
+ % The call to proc_info_has_io_state_pair in
+ % table_gen__process_procs should ensure that we
+ % never get here.
@@ -899,2 +918,2 @@
-:- pred table_gen__var_is_io_state(module_info::in, map(prog_var, type)::in,
- prog_var::in) is semidet.
+:- pred table_gen__var_is_io_state(map(prog_var, type)::in, prog_var::in)
+ is semidet.
@@ -902 +921 @@
-table_gen__var_is_io_state(ModuleInfo, VarTypes, Var) :-
+table_gen__var_is_io_state(VarTypes, Var) :-
@@ -904,9 +923 @@
- table_gen__type_is_io_state(ModuleInfo, VarType).
-
-:- pred table_gen__type_is_io_state(module_info::in, (type)::in) is semidet.
-
-table_gen__type_is_io_state(ModuleInfo, Type) :-
- type_to_type_id(Type, TypeCtor, []),
- type_util__type_id_module(ModuleInfo, TypeCtor, unqualified("io")),
- type_util__type_id_name(ModuleInfo, TypeCtor, "state"),
- type_util__type_id_arity(ModuleInfo, TypeCtor, 0).
+ type_util__type_is_io_state(VarType).
@@ -1238 +1249 @@
- ( table_gen__type_is_io_state(Module, Type) ->
+ ( type_util__type_is_io_state(Type) ->
@@ -1354 +1365 @@
- ( table_gen__type_is_io_state(Module, Type) ->
+ ( type_util__type_is_io_state(Type) ->
--- compiler/trace.m
+++ compiler/trace.m
@@ -296,6 +296,6 @@
- % stage 5: If the procedure has io state arguments, allocate the
- % next slot to hold the saved value of the io sequence
- % number, for use in implementing retry. The number of
- % this slot is recorded in the maybe_io_seq field
- % in the proc layout; if there is no such slot, that
- % field will contain -1.
+ % stage 5: If --trace-table-io is given, allocate the next slot
+ % to hold the saved value of the io sequence number,
+ % for use in implementing retry. The number of this slot
+ % is recorded in the maybe_io_seq field in the proc
+ % layout; if there is no such slot, that field will
+ % contain -1.
@@ -311 +311 @@
- % stage 6: If the procedure lives on the det stack but can put
+ % stage 7: If the procedure lives on the det stack but can put
@@ -319 +319 @@
- % stage 7: If the procedure's evaluation method is memo, loopcheck
+ % stage 8: If the procedure's evaluation method is memo, loopcheck
@@ -352 +352 @@
-trace__reserved_slots(ModuleInfo, ProcInfo, Globals, ReservedSlots,
+trace__reserved_slots(_ModuleInfo, ProcInfo, Globals, ReservedSlots,
@@ -355,0 +356 @@
+ globals__lookup_bool_option(Globals, trace_table_io, TraceTableIo),
@@ -382 +383 @@
- ( proc_info_has_io_state_args(ModuleInfo, ProcInfo, _, _) ->
+ ( TraceTableIo = yes ->
@@ -413 +414 @@
-trace__setup(ModuleInfo, ProcInfo, Globals, TraceSlotInfo, TraceInfo) -->
+trace__setup(_ModuleInfo, ProcInfo, Globals, TraceSlotInfo, TraceInfo) -->
@@ -416,0 +418 @@
+ { globals__lookup_bool_option(Globals, trace_table_io, TraceTableIo) },
@@ -453 +455,2 @@
- { proc_info_has_io_state_args(ModuleInfo, ProcInfo, _, _) ->
+ {
+ TraceTableIo = yes,
@@ -459,0 +463 @@
+ TraceTableIo = no,
@@ -527 +531,13 @@
- ( MaybeRedoLabel = yes(RedoLayoutLabel) ->
+ (
+ MaybeIoSeqSlot = yes(IoSeqLval),
+ trace__stackref_to_string(IoSeqLval, IoSeqStr),
+ string__append_list([
+ FillThreeSlots, "\n",
+ "\t\t", IoSeqStr, " = MR_io_tabling_counter;"
+ ], FillSlotsUptoIoSeq)
+ ;
+ MaybeIoSeqSlot = no,
+ FillSlotsUptoIoSeq = FillThreeSlots
+ ),
+ (
+ MaybeRedoLabel = yes(RedoLayoutLabel),
@@ -533 +549 @@
- FillThreeSlots, "\n",
+ FillSlotsUptoIoSeq, "\n",
@@ -537 +553 @@
- ], FillFourSlots),
+ ], FillSlotsUptoRedo),
@@ -540 +556,2 @@
- FillFourSlots = FillThreeSlots,
+ MaybeRedoLabel = no,
+ FillSlotsUptoRedo = FillSlotsUptoIoSeq,
@@ -568 +585 @@
- FillSixSlots,
+ FillSlotsUptoTrail,
@@ -570 +587 @@
- ], FillCondSlots)
+ ], FillSlotsUptoMaxfr)
@@ -573 +590 @@
- FillCondSlots = FillSixSlots
+ FillSlotsUptoMaxfr = FillSlotsUptoTrail
@@ -795 +812 @@
- DeclStmt = "\t\tCode *MR_jumpaddr;\n",
+ DeclStmt = "\t\tMR_Code *MR_jumpaddr;\n",
--- library/io.m
+++ library/io.m
@@ -3543 +3543,2 @@
- [may_call_mercury, thread_safe], "
+ [may_call_mercury, tabled_for_io, thread_safe],
+"
@@ -3549 +3550,2 @@
- [may_call_mercury, thread_safe], "
+ [may_call_mercury, tabled_for_io, thread_safe],
+"
@@ -3555 +3557,2 @@
- [may_call_mercury, thread_safe], "
+ [may_call_mercury, tabled_for_io, thread_safe],
+"
@@ -3561 +3564,2 @@
- [may_call_mercury, thread_safe], "
+ [may_call_mercury, tabled_for_io, thread_safe],
+"
@@ -3570 +3574,2 @@
- [will_not_call_mercury, thread_safe], "
+ [will_not_call_mercury, tabled_for_io, thread_safe],
+"
--- library/table_builtin.m
+++ library/table_builtin.m
@@ -320,0 +321,18 @@
+ % This procedure should be called exactly once for each I/O action.
+ % If I/O tabling is enabled, this predicate will increment the I/O
+ % action counter, and will check if this action should be tabled.
+ % If not, it fails. If yes, it succeeds, and binds the output
+ % arguments, which are, in order:
+ %
+ % - The root trie node for all I/O actions. This is similar to
+ % the per-procedure tabling pointers, but it is shared by all
+ % I/O actions.
+ % - the I/O action number of this action.
+ % - The I/O action number of the first action in the tabled range.
+ %
+ % After the first tabled action, the root trie node will point to a
+ % (dynamically expandable) array of trie nodes. The trie node for
+ % I/O action number Counter is at offset Counter - Start in this array,
+ % where Start is the I/O action number of the first tabled action.
+ % The three output parameters together specify this location.
+
@@ -322,0 +341,6 @@
+ % This procedure should be called exactly once for each I/O action
+ % for which table_io_in_range returns true. Given the trie node
+ % for a given I/O action number, it returns true iff that action has
+ % been carried out before (i.e. the action is now being reexecuted
+ % after a retry command in the debugger).
+
@@ -324,0 +349,5 @@
+ % This predicate simply copies the input I/O state to become the output
+ % I/O state. It is used only because it is easier to get the insts
+ % right by calling this procedure than by hand-writing insts for a
+ % unification.
+
@@ -326,0 +356,2 @@
+ % N.B. interface continued below
+
@@ -334,3 +365,3 @@
-% Phase 0 consists of Mercury code executed prior to the first debugger event.
-% Even if main/2 is traced, this will include the initialization of the I/O
-% system itself. During this phase, MR_io_tabling_enabled will be FALSE.
+% Phase UNINIT consists of Mercury code executed prior to the first debugger
+% event. Even if main/2 is traced, this will include the initialization of the
+% I/O system itself. During this phase, MR_io_tabling_enabled will be FALSE.
@@ -338,5 +369,5 @@
-% Phase 1 consists of Mercury code during whose execution the user does not
-% need safe retry across I/O, probably because he/she does not require retry at
-% all. During this phase, MR_io_tabling_enabled will be TRUE while we ensure
-% that table_io_range returns FALSE by setting MR_io_tabling_start to the
-% highest possible value.
+% Phase BEFORE consists of Mercury code during whose execution the user does
+% not need safe retry across I/O, probably because he/she does not require
+% retry at all. During this phase, MR_io_tabling_enabled will be TRUE while
+% we ensure that table_io_range returns FALSE by setting MR_io_tabling_start
+% to the highest possible value.
@@ -344,5 +375,6 @@
-% Phase 2 consists of Mercury code during whose execution the user does need
-% safe retry across I/O. During this phase, MR_io_tabling_enabled will be TRUE,
-% and MR_io_tabling_start will be set to the value of MR_io_tabling_counter on
-% entry to phase 2. We will ensure that table_io_in_range returns TRUE by
-% setting MR_io_tabling_end to the highest possible value.
+% Phase DURING consists of Mercury code during whose execution the user does
+% need safe retry across I/O. During this phase, MR_io_tabling_enabled will be
+% TRUE, and MR_io_tabling_start will be set to the value of
+% MR_io_tabling_counter on entry to phase DURING. We will ensure that
+% table_io_in_range returns TRUE by setting MR_io_tabling_end to the highest
+% possible value.
@@ -350,6 +382,6 @@
-% Phase 3 again consists of Mercury code during whose execution the user does
-% not need safe retry across I/O. During this phase, MR_io_tabling_enabled will
-% be TRUE, MR_io_tabling_start will contain the value of MR_io_tabling_counter
-% at the time of the entry to phase 2, while MR_io_tabling_end will contain the
-% value of MR_io_tabling_counter at the end of phase 2, thus ensuring that
-% table_io_in_range again returns FALSE.
+% Phase AFTER again consists of Mercury code during whose execution the user
+% does not need safe retry across I/O. During this phase, MR_io_tabling_enabled
+% will be TRUE, MR_io_tabling_start will contain the value of
+% MR_io_tabling_counter at the time of the entry to phase DURING, while
+% MR_io_tabling_end will contain the value of MR_io_tabling_counter at the end
+% of phase DURING, thus ensuring that table_io_in_range again returns FALSE.
@@ -357,2 +389,2 @@
-% The transition from phase 0 to phase 1 will occur during the initialization
-% of the debugger, at the first trace event.
+% The transition from phase UNINIT to phase BEFORE will occur during the
+% initialization of the debugger, at the first trace event.
@@ -360,6 +392,6 @@
-% The transition from phase 1 to phase 2 will occur when the user issues the
-% "table_io start" command, while the transition from phase 2 to phase 3 will
-% occur when the user issues the "table_io end" command. The user may automate
-% entry into phase 2 by putting "table_io start" into a .mdbrc file. Of course
-% the program will never enter phase 2 or phase 3 if the user never gives the
-% commands that start those phases.
+% The transition from phase BEFORE to phase DURING will occur when the user
+% issues the "table_io start" command, while the transition from phase DURING
+% to phase AFTER will occur when the user issues the "table_io end" command.
+% The user may automate entry into phase DURING by putting "table_io start"
+% into a .mdbrc file. Of course the program will never enter phase DURING or
+% phase AFTER if the user never gives the commands that start those phases.
@@ -381 +413 @@
- T = (Word) &MR_io_tabling_pointer;
+ T = (MR_Word) &MR_io_tabling_pointer;
@@ -830,2 +862 @@
- % Save any type of answer in the given answer block at the given
- % offset.
+ % Save an I/O state in the given answer block at the given offset.
@@ -859,2 +890 @@
- % Restore any type of answer from the given answer block at the
- % given offset.
+ % Restore an I/O state from the given answer block at the given offset.
--- runtime/mercury_conf.h.in 2000/10/30 10:54:39
+++ runtime/mercury_conf.h.in 2000/08/17 09:58:06 1.32
@@ -50,13 +50,6 @@
*/
#undef MR_INTEGER_LENGTH_MODIFIER
-/*
-** MR_INTEGER_MAX: the maximum MR_Integer value.
-** MR_UNSIGNED_MAX: the maximum MR_Unsigned value.
-*/
-#undef MR_INTEGER_MAX
-#undef MR_UNSIGNED_MAX
-
/*
** MR_INT_LEAST64_TYPE:
** This must be a C integral type (e.g. int, long, long long)
--- runtime/mercury_tabling.h 2000/10/22 22:51:00
+++ runtime/mercury_tabling.h 2000/10/11 03:00:26 1.23
@@ -65,7 +65,7 @@
** important that all members be the same size; this is why the simple table
** status field is an (unsigned) integer, not an enum.
**
+** The integer field is by generic code that does not know what kind of node
-** The integer field is for generic code that does not know what kind of node
** the node will be; this means initialization. A value of zero means the node
** is uninitialized; this must be true for all members. (Also, see below on
** duplicate detection.)
@@ -86,7 +86,7 @@
** the chain of trie nodes given by the input arguments of the tabled subgoal,
** will be overwritten by a pointer to the answer block containing the output
** arguments when the goal succeeds; the MR_SIMPLETABLE_SUCCEEDED status code
+** is used only when the goal has no outputs, and this no answer block.
-** is used only when the goal has no outputs, and thus no answer block.
** This is why MR_SIMPLETABLE_SUCCEEDED must have the highest value, and
** why code looking at MR_simpletable_status must test for success with
** "table->MR_simpletable_status >= MR_SIMPLETABLE_SUCCEEDED".
--- runtime/mercury_trace_base.c
+++ runtime/mercury_trace_base.c
@@ -98,0 +99,12 @@
+/*
+** I/O tabling is documented in library/table_builtin.m
+*/
+
+MR_IoTablingPhase MR_io_tabling_phase = MR_IO_TABLING_UNINIT;
+bool MR_io_tabling_enabled = FALSE;
+MR_TableNode MR_io_tabling_pointer = { 0 };
+MR_Unsigned MR_io_tabling_counter = 0;
+MR_Unsigned MR_io_tabling_counter_hwm = 0;
+MR_Unsigned MR_io_tabling_start = 0;
+MR_Unsigned MR_io_tabling_end = 0;
+
--- runtime/mercury_wrapper.c 2000/11/06 01:49:57
+++ runtime/mercury_wrapper.c 2000/11/05 12:04:18 1.76
@@ -207,13 +207,11 @@
void (*MR_io_print_to_cur_stream)(MR_Word, MR_Word);
void (*MR_io_print_to_stream)(MR_Word, MR_Word, MR_Word);
+void (*MR_DI_output_current_ptr)(MR_Integer, MR_Integer, MR_Integer, MR_Word, MR_String,
+ MR_String, MR_Integer, MR_Integer, MR_Integer, MR_Word, MR_String, MR_Word, MR_Word);
-void (*MR_DI_output_current_ptr)(MR_Integer, MR_Integer, MR_Integer,
- MR_Word, MR_String, MR_String, MR_Integer, MR_Integer,
- MR_Integer, MR_Word, MR_String, MR_Word, MR_Word);
/* normally ML_DI_output_current (output_current/13) */
+bool (*MR_DI_found_match)(MR_Integer, MR_Integer, MR_Integer, MR_Word, MR_String, MR_String,
+ MR_Integer, MR_Integer, MR_Integer, MR_Word, MR_String, MR_Word);
-bool (*MR_DI_found_match)(MR_Integer, MR_Integer, MR_Integer, MR_Word,
- MR_String, MR_String, MR_Integer, MR_Integer, MR_Integer,
- MR_Word, MR_String, MR_Word);
/* normally ML_DI_found_match (output_current/12) */
void (*MR_DI_read_request_from_socket)(MR_Word, MR_Word *, MR_Integer *);
@@ -231,18 +229,6 @@
void (*MR_address_of_trace_interrupt_handler)(void);
void (*MR_register_module_layout)(const MR_Module_Layout *);
-
-/*
-** These variables are documented in library/table_builtin.m.
-*/
-
-int MR_io_tabling_phase = 0;
-bool MR_io_tabling_enabled = FALSE;
-MR_TableNode MR_io_tabling_pointer = { 0 };
-MR_Unsigned MR_io_tabling_counter = 0;
-MR_Unsigned MR_io_tabling_counter_hwm = 0;
-MR_Unsigned MR_io_tabling_start = 0;
-MR_Unsigned MR_io_tabling_end = 0;
#ifdef USE_GCC_NONLOCAL_GOTOS
--- runtime/mercury_wrapper.h 2000/11/06 01:49:57
+++ runtime/mercury_wrapper.h 2000/11/05 12:04:19 1.37
@@ -153,14 +153,6 @@
*/
extern void (*MR_register_module_layout)(const MR_Module_Layout *);
-extern int MR_io_tabling_phase;
-extern bool MR_io_tabling_enabled;
-extern MR_TableNode MR_io_tabling_pointer;
-extern MR_Unsigned MR_io_tabling_counter;
-extern MR_Unsigned MR_io_tabling_counter_hwm;
-extern MR_Unsigned MR_io_tabling_start;
-extern MR_Unsigned MR_io_tabling_end;
-
extern void do_init_modules(void);
extern void do_init_modules_type_tables(void);
extern void do_init_modules_debugger(void);
--- tabled_read.data
+++ tabled_read.data
@@ -1,0 +2,2 @@
+456
+789
--- tabled_read.inp
+++ tabled_read.inp
@@ -2,0 +3,2 @@
+context none
+table_io
@@ -8 +9,0 @@
-table_io
@@ -10,0 +12,7 @@
+finish -n
+print *
+table_io end
+continue
+finish -n
+print *
+retry
--- tabled_read.m
+++ tabled_read.m
@@ -1,1 +1,2 @@
+% We define our own I/O primitives, in case the library was compiled without
+% IO tabling.
+
% IO tabling.
@@ -15,2 +18,2 @@
- io__open_input("tabled_read.data", Res),
- ( { Res = ok(Stream) } ->
+ tabled_read__open_input("tabled_read.data", Res, Stream),
+ ( { Res = 0 } ->
@@ -18,2 +21,3 @@
- io__write_int(N),
- io__write_string("\n")
+ tabled_read__write_int(N),
+ tabled_read__test(Stream, 0, M),
+ tabled_read__write_int(M)
@@ -24 +28 @@
-:- pred tabled_read__test(io__input_stream::in, int::in, int::out,
+:- pred tabled_read__test(c_pointer::in, int::in, int::out,
@@ -39,2 +43,12 @@
-% We define our own version of io__read_char_code, in case the library
-% was compiled without IO tabling.
+:- pragma c_header_code("#include <stdio.h>").
+
+:- pred tabled_read__open_input(string::in, int::out, c_pointer::out,
+ io__state::di, io__state::uo) is det.
+
+:- pragma c_code(tabled_read__open_input(FileName::in, Res::out, Stream::out,
+ IO0::di, IO::uo), [will_not_call_mercury, tabled_for_io],
+"
+ Stream = (MR_Word) fopen((const char *) FileName, ""r"");
+ Res = Stream? 0 : -1;
+ IO = IO0;
+").
@@ -42 +56 @@
-:- pred tabled_read__read_char_code(io__input_stream::in, int::out,
+:- pred tabled_read__read_char_code(c_pointer::in, int::out,
@@ -45,4 +59,4 @@
-:- pragma c_code(tabled_read__read_char_code(File::in, CharCode::out,
- IO0::di, IO::uo), [will_not_call_mercury], "
- extern int mercury_getc(MercuryFile* mf);
- CharCode = mercury_getc((MercuryFile *) File);
+:- pragma c_code(tabled_read__read_char_code(Stream::in, CharCode::out,
+ IO0::di, IO::uo), [will_not_call_mercury, tabled_for_io],
+"
+ CharCode = getc((FILE *) Stream);
@@ -52,10 +66,8 @@
-% % We define our own version of io__write_string, in case the library
-% % was compiled without IO tabling.
-%
-% :- pragma c_code(tabled_read__write_string(Stream::in, Message::in,
-% IO0::di, IO::uo), [may_call_mercury, thread_safe],
-% "{
-% MercuryFile *stream = (MercuryFile *) Stream;
-% mercury_print_string(stream, Message);
-% update_io(IO0, IO);
-% }").
+:- pred tabled_read__write_int(int::in, io__state::di, io__state::uo) is det.
+
+:- pragma c_code(tabled_read__write_int(N::in,
+ IO0::di, IO::uo), [may_call_mercury, thread_safe],
+"{
+ printf(""%d\n"", (int) N);
+ IO = IO0;
+}").
--- trace/mercury_trace_internal.c
+++ trace/mercury_trace_internal.c
@@ -160 +159,0 @@
-static void MR_print_unsigned(FILE *fp, MR_Unsigned value);
@@ -345,3 +344,3 @@
- MR_io_tabling_phase = 1;
- MR_io_tabling_start = MR_UNSIGNED_MAX;
- MR_io_tabling_end = MR_UNSIGNED_MAX;
+ MR_io_tabling_phase = MR_IO_TABLING_BEFORE;
+ MR_io_tabling_start = MR_IO_ACTION_MAX;
+ MR_io_tabling_end = MR_IO_ACTION_MAX;
@@ -1067 +1066 @@
- do_init_modules();
+ MR_do_init_modules();
@@ -1837 +1836 @@
- do_init_modules();
+ MR_do_init_modules();
@@ -1848 +1847 @@
- do_init_modules();
+ MR_do_init_modules();
@@ -1875 +1874,2 @@
- if (MR_io_tabling_phase == 1) {
+ if (MR_io_tabling_phase == MR_IO_TABLING_BEFORE)
+ {
@@ -1878 +1878,2 @@
- } else if (MR_io_tabling_phase == 2) {
+ } else if (MR_io_tabling_phase == MR_IO_TABLING_DURING)
+ {
@@ -1881 +1882,2 @@
- } else if (MR_io_tabling_phase == 3) {
+ } else if (MR_io_tabling_phase == MR_IO_TABLING_AFTER)
+ {
@@ -1889,2 +1891,2 @@
- if (MR_io_tabling_phase == 1) {
- MR_io_tabling_phase = 2;
+ if (MR_io_tabling_phase == MR_IO_TABLING_BEFORE) {
+ MR_io_tabling_phase = MR_IO_TABLING_DURING;
@@ -1892 +1894 @@
- MR_io_tabling_end = MR_UNSIGNED_MAX;
+ MR_io_tabling_end = MR_IO_ACTION_MAX;
@@ -1894 +1896,2 @@
- } else if (MR_io_tabling_phase == 2) {
+ } else if (MR_io_tabling_phase == MR_IO_TABLING_DURING)
+ {
@@ -1897 +1900,2 @@
- } else if (MR_io_tabling_phase == 3) {
+ } else if (MR_io_tabling_phase == MR_IO_TABLING_AFTER)
+ {
@@ -1905 +1909,2 @@
- if (MR_io_tabling_phase == 1) {
+ if (MR_io_tabling_phase == MR_IO_TABLING_BEFORE)
+ {
@@ -1908,2 +1913,3 @@
- } else if (MR_io_tabling_phase == 2) {
- MR_io_tabling_phase = 3;
+ } else if (MR_io_tabling_phase == MR_IO_TABLING_DURING)
+ {
+ MR_io_tabling_phase = MR_IO_TABLING_AFTER;
@@ -1912 +1918,2 @@
- } else if (MR_io_tabling_phase == 3) {
+ } else if (MR_io_tabling_phase == MR_IO_TABLING_AFTER)
+ {
@@ -2082,12 +2089 @@
- fprintf(fp, "%s = ", var);
- MR_print_unsigned(fp, value);
- fprintf(fp, "\n");
-}
-
-static void
-MR_print_unsigned(FILE *fp, MR_Unsigned value)
-{
- char buf[20];
-
- sprintf(buf, "%%%su", MR_INTEGER_LENGTH_MODIFIER);
- fprintf(fp, buf, value);
+ fprintf(fp, "%s = %" MR_INTEGER_LENGTH_MODIFIER "u\n", var, value);
--- runtime/mercury_trace_base.h 2000/08/03 06:19:00 1.14
+++ runtime/mercury_trace_base.h 2000/11/28 10:05:47
@@ -18,6 +18,7 @@
#include <stdio.h>
#include "mercury_stack_layout.h"
#include "mercury_std.h"
+#include "mercury_tabling.h" /* for MR_TableNode */
/*
** This enum should EXACTLY match the definition of the `trace_port_type'
@@ -48,7 +49,8 @@
#define MR_trace_incr_seq() ((MR_Word) ++MR_trace_call_seqno)
#define MR_trace_incr_depth() ((MR_Word) ++MR_trace_call_depth)
-#define MR_trace_reset_depth(d) (MR_trace_call_depth = (MR_Unsigned) (d))
+#define MR_trace_reset_depth(d) (MR_trace_call_depth = \
+ (MR_Unsigned) (d))
/*
** MR_trace is called from Mercury modules compiled with tracing.
@@ -110,6 +112,48 @@
extern MR_Unsigned MR_trace_event_number;
extern MR_Bool MR_trace_from_full;
+
+/*
+** The details of I/O tabling are documented in library/table_builtin.m.
+*/
+
+typedef enum {
+ /* from program start to first debugger event */
+ MR_IO_TABLING_UNINIT,
+
+ /* from first debugger event to "table_io start" command */
+ MR_IO_TABLING_BEFORE,
+
+ /* from "table_io start" command to "table_io end" command */
+ MR_IO_TABLING_DURING,
+
+ /* from "table_io end" command to program exit */
+ MR_IO_TABLING_AFTER
+} MR_IoTablingPhase;
+
+typedef MR_Unsigned MR_IoActionNum;
+
+#define MR_IO_ACTION_MAX ((MR_IoActionNum) -1)
+
+extern MR_IoTablingPhase MR_io_tabling_phase;
+
+/* True iff I/O tabling is enabled. */
+extern bool MR_io_tabling_enabled;
+
+/* The root of the trie that we use for tabling I/O. */
+extern MR_TableNode MR_io_tabling_pointer;
+
+/* The I/O action number of the last I/O action. */
+extern MR_IoActionNum MR_io_tabling_counter;
+
+/* The highest I/O action number ever reached ("hwm" = "high water mark"). */
+extern MR_IoActionNum MR_io_tabling_counter_hwm;
+
+/* The highest I/O action number which is too early to be tabled. */
+extern MR_IoActionNum MR_io_tabling_start;
+
+/* The highest I/O action number which is to be tabled. */
+extern MR_IoActionNum MR_io_tabling_end;
/*
** These functions will report the number of the last event,
--------------------------------------------------------------------------
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