Add support for the MLDS back-end (i.e. the `--high-level-code'

Estimated hours taken: 10

Add support for the MLDS back-end (i.e. the `--high-level-code'
option) to various parts of the standard library.

library/benchmarking.m:
	Add `#ifndef MR_HIGHLEVEL_CODE' to ifdef out the parts
	of `report_stats' which depend on the details of the
	low-level execution model.

	Rewrite benchmark_det and benchmark_nondet using
	impure Mercury with `pragma c_code' fragments,
	rather than using low-level C code.
	The low-level C code was a maintenance problem
	(e.g. I don't think it was restoring the
	MR_ticket_counter properly in trailing grades)
	and this way avoids the need to duplicate the
	hand-written code for the MLDS back-end.

library/exception.m:
	Implement exception handling for the MLDS back-end,
	using setjmp() and longjmp().

library/math.m:
	Add `#ifndef MR_HIGHLEVEL_CODE' around the call to
	MR_dump_stack(), since that code requires the
	low-level execution model.

library/gc.m:
	Add `#ifndef MR_HIGHLEVEL_CODE' around the calls to
	MR_clear_zone_for_GC(), since they depend on the details
	of the low-level execution model and are not required
	for --high-level-code.
This commit is contained in:
Fergus Henderson
1999-12-21 10:33:58 +00:00
parent 5eeb100124
commit 78339a003f
4 changed files with 476 additions and 246 deletions

View File

@@ -15,7 +15,6 @@
%-----------------------------------------------------------------------------%
:- module benchmarking.
:- interface.
% `report_stats' is a non-logical procedure intended for use in profiling
@@ -53,7 +52,10 @@
:- mode benchmark_nondet(pred(in, out) is nondet, in, out, in, out)
is cc_multi.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module int, std_util.
:- pragma c_header_code("
@@ -139,7 +141,9 @@ void
ML_report_stats(void)
{
int time_at_prev_stat;
#ifndef MR_HIGHLEVEL_CODE
MercuryEngine *eng;
#endif
#ifdef PROFILE_MEMORY
int num_table_entries;
ML_memprof_report_entry table[MEMORY_PROFILE_SIZE];
@@ -152,17 +156,24 @@ ML_report_stats(void)
time_at_prev_stat = time_at_last_stat;
time_at_last_stat = MR_get_user_cpu_miliseconds();
#ifdef MR_HIGHLEVEL_CODE
eng = MR_get_engine();
#endif
fprintf(stderr,
""[Time: +%.3fs, %.3fs, D Stack: %.3fk, ND Stack: %.3fk,"",
""[Time: +%.3fs, %.3fs,"",
(time_at_last_stat - time_at_prev_stat) / 1000.0,
(time_at_last_stat - time_at_start) / 1000.0,
(time_at_last_stat - time_at_start) / 1000.0
);
#ifndef MR_HIGHLEVEL_CODE
fprintf(stderr, "" D Stack: %.3fk, ND Stack: %.3fk,"",
((char *) MR_sp - (char *)
eng->context.detstack_zone->min) / 1024.0,
((char *) MR_maxfr - (char *)
eng->context.nondetstack_zone->min) / 1024.0
);
#endif
#ifdef CONSERVATIVE_GC
{ char local_var;
@@ -539,255 +550,107 @@ ML_memory_profile_compare_final(const void *i1, const void *i2)
%-----------------------------------------------------------------------------%
:- external(benchmark_det/5).
:- external(benchmark_nondet/5).
:- pragma promise_pure(benchmark_det/5).
benchmark_det(Pred, In, Out, Repeats, Time) :-
impure get_user_cpu_miliseconds(StartTime),
impure benchmark_det_loop(Pred, In, Out, Repeats),
impure get_user_cpu_miliseconds(EndTime),
Time0 = StartTime - EndTime,
cc_multi_equal(Time0, Time).
:- pragma c_code("
:- impure pred benchmark_det_loop(pred(T1, T2), T1, T2, int).
:- mode benchmark_det_loop(pred(in, out) is det, in, out, in) is det.
benchmark_det_loop(Pred, In, Out, Repeats) :-
% The call to do_nothing/1 here is to make sure the compiler
% doesn't optimize away the call to `Pred'.
Pred(In, Out0),
impure do_nothing(Out0),
( Repeats > 1 ->
impure benchmark_det_loop(Pred, In, Out, Repeats - 1)
;
Out = Out0
).
:- pragma promise_pure(benchmark_nondet/5).
benchmark_nondet(Pred, In, Count, Repeats, Time) :-
impure get_user_cpu_miliseconds(StartTime),
impure benchmark_nondet_loop(Pred, In, Count, Repeats),
impure get_user_cpu_miliseconds(EndTime),
Time0 = StartTime - EndTime,
cc_multi_equal(Time0, Time).
:- impure pred benchmark_nondet_loop(pred(T1, T2), T1, int, int).
:- mode benchmark_nondet_loop(pred(in, out) is nondet, in, out, in) is det.
benchmark_nondet_loop(Pred, In, Count, Repeats) :-
impure new_int_reference(0, SolutionCounter),
(
impure repeat(Repeats),
impure update_ref(SolutionCounter, 0),
Pred(In, Out0),
impure do_nothing(Out0),
impure incr_ref(SolutionCounter),
fail
;
true
),
semipure ref_value(SolutionCounter, Count).
:- impure pred repeat(int::in) is nondet.
repeat(N) :-
N > 0,
( true ; impure repeat(N - 1) ).
:- impure pred get_user_cpu_miliseconds(int::out) is det.
:- pragma c_code(get_user_cpu_miliseconds(Time::out), [will_not_call_mercury],
"
Time = MR_get_user_cpu_miliseconds();
").
/*
INIT mercury_benchmarking_init_benchmark
ENDINIT
** To prevent the C compiler from optimizing the benchmark code
** away, we assign the benchmark output to a volatile global variable.
*/
/*
** :- pred benchmark_nondet(pred(T1, T2), T1, int, int, int).
** :- mode benchmark_nondet(pred(in, out) is nondet, in, out, in, out) is det.
**
** :- pred benchmark_det(pred(T1, T2), T1, int, int, int).
** :- mode benchmark_det(pred(in, out) is det, in, out, in, out) is det.
**
** Polymorphism will add two extra input parameters, type_infos for T1 and T2,
** which we don't use. These will be in r1 and r2, while the closure will be
** in r3, and the input data in r4. The repetition count will be in r5.
**
** The first output is a count of solutions for benchmark_nondet and the
** actual solution for benchmark_det; the second output for both is the
** time taken in milliseconds.
*/
#ifdef MR_USE_TRAIL
#define BENCHMARK_NONDET_STACK_SLOTS 7
#else
#define BENCHMARK_NONDET_STACK_SLOTS 6
#endif
Define_extern_entry(mercury__benchmarking__benchmark_nondet_5_0);
Declare_label(mercury__benchmarking__benchmark_nondet_5_0_i1);
Declare_label(mercury__benchmarking__benchmark_nondet_5_0_i2);
MR_MAKE_PROC_LAYOUT(mercury__benchmarking__benchmark_nondet_5_0,
MR_DETISM_NON, BENCHMARK_NONDET_STACK_SLOTS, MR_LONG_LVAL_TYPE_UNKNOWN,
MR_PREDICATE, ""benchmarking"", ""benchmark_nondet"", 5, 0);
MR_MAKE_INTERNAL_LAYOUT(mercury__benchmarking__benchmark_nondet_5_0, 1);
MR_MAKE_INTERNAL_LAYOUT(mercury__benchmarking__benchmark_nondet_5_0, 2);
Declare_entry(mercury__do_call_closure);
BEGIN_MODULE(benchmark_nondet_module)
init_entry_sl(mercury__benchmarking__benchmark_nondet_5_0);
MR_INIT_PROC_LAYOUT_ADDR(mercury__benchmarking__benchmark_nondet_5_0);
init_label_sl(mercury__benchmarking__benchmark_nondet_5_0_i1);
init_label_sl(mercury__benchmarking__benchmark_nondet_5_0_i2);
BEGIN_CODE
Define_entry(mercury__benchmarking__benchmark_nondet_5_0);
/*
** Create a nondet stack frame. The contents of the slots:
**
** MR_framevar(1): the closure to be called.
** MR_framevar(2): the input for the closure.
** MR_framevar(3): the number of iterations left to be done.
** MR_framevar(4): the number of solutions found so far.
** MR_framevar(5): the time at entry to the first iteration.
** MR_framevar(6): the saved heap pointer
** MR_framevar(7): the saved trail pointer (if trailing enabled)
**
** We must make that the closure is called at least once,
** otherwise the count we return isn't valid.
*/
MR_mkframe(""benchmark_nondet"", BENCHMARK_NONDET_STACK_SLOTS,
LABEL(mercury__benchmarking__benchmark_nondet_5_0_i2));
MR_framevar(1) = r3;
MR_framevar(2) = r4;
/* r5 is the repetition count */
if ((Integer) r5 <= 0) {
MR_framevar(3) = 1;
} else {
MR_framevar(3) = r5;
}
MR_framevar(4) = 0;
mark_hp(MR_framevar(6));
#ifdef MR_USE_TRAIL
MR_framevar(7) = (Word) MR_trail_ptr;
#endif
MR_framevar(5) = MR_get_user_cpu_miliseconds();
/* call the higher-order pred closure that we were passed in r3 */
r1 = r3;
r2 = (Word) 1; /* the higher-order call has 1 extra input argument */
r3 = (Word) 1; /* the higher-order call has 1 extra output argument */
/* r4 already has the extra input argument */
call(ENTRY(mercury__do_call_closure),
LABEL(mercury__benchmarking__benchmark_nondet_5_0_i1),
LABEL(mercury__benchmarking__benchmark_nondet_5_0));
Define_label(mercury__benchmarking__benchmark_nondet_5_0_i1);
update_prof_current_proc(
LABEL(mercury__benchmarking__benchmark_nondet_5_0));
/* we found a solution */
MR_framevar(4) = MR_framevar(4) + 1;
MR_redo();
Define_label(mercury__benchmarking__benchmark_nondet_5_0_i2);
update_prof_current_proc(
LABEL(mercury__benchmarking__benchmark_nondet_5_0));
/* no more solutions for this iteration, so mark it completed */
MR_framevar(3) = MR_framevar(3) - 1;
/* we can now reclaim memory by resetting the heap pointer */
restore_hp(MR_framevar(6));
#ifdef MR_USE_TRAIL
/* ... and the trail pointer */
MR_trail_ptr = (MR_TrailEntry *) MR_framevar(7);
#endif
/* are there any other iterations? */
if (MR_framevar(3) > 0) {
/* yes, so reset the solution counter */
/* and then set up the call just like last time */
MR_framevar(4) = 0;
r1 = MR_framevar(1);
r2 = (Word) 1;
r3 = (Word) 1;
r4 = MR_framevar(2);
call(ENTRY(mercury__do_call_closure),
LABEL(mercury__benchmarking__benchmark_nondet_5_0_i1),
LABEL(mercury__benchmarking__benchmark_nondet_5_0));
}
/* no more iterations */
r1 = MR_framevar(4);
r2 = MR_get_user_cpu_miliseconds() - MR_framevar(5);
MR_succeed_discard();
END_MODULE
#undef BENCHMARK_NONDET_STACK_SLOTS
#ifdef MR_USE_TRAIL
#define BENCHMARK_DET_STACK_SLOTS 7
#else
#define BENCHMARK_DET_STACK_SLOTS 6
#endif
Define_extern_entry(mercury__benchmarking__benchmark_det_5_0);
Declare_label(mercury__benchmarking__benchmark_det_5_0_i1);
MR_MAKE_PROC_LAYOUT(mercury__benchmarking__benchmark_det_5_0,
MR_DETISM_NON, BENCHMARK_DET_STACK_SLOTS, MR_LONG_LVAL_STACKVAR(6),
MR_PREDICATE, ""benchmarking"", ""benchmark_nondet"", 5, 0);
MR_MAKE_INTERNAL_LAYOUT(mercury__benchmarking__benchmark_det_5_0, 1);
BEGIN_MODULE(benchmark_det_module)
init_entry_sl(mercury__benchmarking__benchmark_det_5_0);
MR_INIT_PROC_LAYOUT_ADDR(mercury__benchmarking__benchmark_det_5_0);
init_label_sl(mercury__benchmarking__benchmark_det_5_0_i1);
BEGIN_CODE
Define_entry(mercury__benchmarking__benchmark_det_5_0);
/*
** Create a det stack frame. The contents of the slots:
**
** MR_stackvar(1): the closure to be called.
** MR_stackvar(2): the input for the closure.
** MR_stackvar(3): the number of iterations left to be done.
** MR_stackvar(4): the time at entry to the first iteration.
** MR_stackvar(5): the saved heap pointer
** MR_stackvar(6): the return address.
** MR_stackvar(7): the saved trail pointer (if trailing enabled)
**
** We must make that the closure is called at least once,
** otherwise the count we return isn't valid.
*/
MR_incr_sp(BENCHMARK_DET_STACK_SLOTS);
#ifdef MR_USE_TRAIL
MR_stackvar(7) = (Word) MR_trail_ptr;
#endif
MR_stackvar(6) = (Word) MR_succip;
mark_hp(MR_stackvar(5));
MR_stackvar(1) = r3;
MR_stackvar(2) = r4;
/* r5 is the repetition count */
if ((Integer) r5 <= 0) {
MR_stackvar(3) = 1;
} else {
MR_stackvar(3) = r5;
}
MR_stackvar(4) = MR_get_user_cpu_miliseconds();
/* call the higher-order pred closure that we were passed in r3 */
r1 = r3;
r2 = (Word) 1; /* the higher-order call has 1 extra input argument */
r3 = (Word) 1; /* the higher-order call has 1 extra output argument */
/* r4 already has the extra input argument */
call(ENTRY(mercury__do_call_closure),
LABEL(mercury__benchmarking__benchmark_det_5_0_i1),
LABEL(mercury__benchmarking__benchmark_det_5_0));
Define_label(mercury__benchmarking__benchmark_det_5_0_i1);
update_prof_current_proc(
LABEL(mercury__benchmarking__benchmark_det_5_0));
/* mark current iteration completed */
MR_stackvar(3) = MR_stackvar(3) - 1;
/* are there any other iterations? */
if (MR_stackvar(3) > 0) {
/* yes, so set up the call just like last time */
#ifdef MR_USE_TRAIL
/* Restore the trail... */
MR_TrailEntry *old_trail_ptr = (MR_TrailEntry *) MR_stackvar(7);
MR_untrail_to(old_trail_ptr, MR_undo);
MR_trail_ptr = old_trail_ptr;
#endif
restore_hp(MR_stackvar(5));
r1 = MR_stackvar(1);
r2 = (Word) 1;
r3 = (Word) 1;
r4 = MR_stackvar(2);
call(ENTRY(mercury__do_call_closure),
LABEL(mercury__benchmarking__benchmark_det_5_0_i1),
LABEL(mercury__benchmarking__benchmark_det_5_0));
}
/* no more iterations */
/* r1 already contains the right value */
r2 = MR_get_user_cpu_miliseconds() - MR_stackvar(4);
MR_succip = (Word *) MR_stackvar(6);
MR_decr_sp(BENCHMARK_DET_STACK_SLOTS);
proceed();
END_MODULE
#undef BENCHMARK_DET_STACK_SLOTS
void mercury_benchmarking_init_benchmark(void); /* suppress gcc warning */
void mercury_benchmarking_init_benchmark(void) {
benchmark_nondet_module();
benchmark_det_module();
}
:- pragma c_header_code("
volatile Word ML_benchmarking_dummy_word;
").
:- impure pred do_nothing(T::in) is det.
:- pragma c_code(do_nothing(X::in), [will_not_call_mercury, thread_safe], "
ML_benchmarking_dummy_word = (Word) X;
").
%-----------------------------------------------------------------------------%
% Impure integer references.
% This type is implemented in C.
:- type int_reference ---> int_reference(c_pointer).
% Create a new int_reference given a term for it to reference.
:- impure pred new_int_reference(int::in, int_reference::out) is det.
:- pragma inline(new_int_reference/2).
:- pragma c_code(new_int_reference(X::in, Ref::out), will_not_call_mercury, "
incr_hp(Ref, 1);
*(Integer *)Ref = X;
").
:- impure pred incr_ref(int_reference::in) is det.
incr_ref(Ref) :-
semipure ref_value(Ref, X),
impure update_ref(Ref, X + 1).
:- semipure pred ref_value(int_reference::in, int::out) is det.
:- pragma inline(ref_value/2).
:- pragma c_code(ref_value(Ref::in, X::out), will_not_call_mercury, "
X = *(Integer *) Ref;
").
:- impure pred update_ref(int_reference::in, T::in) is det.
:- pragma inline(update_ref/2).
:- pragma c_code(update_ref(Ref::in, X::in), will_not_call_mercury, "
*(Integer *) Ref = X;
").
%-----------------------------------------------------------------------------%

View File

@@ -448,8 +448,367 @@ wrap_exception(Exception, exception(Exception)).
:- external(builtin_catch/3).
%-----------------------------------------------------------------------------%
%
% The --high-level-code implementation
%
:- pragma c_header_code("
#ifdef MR_HIGHLEVEL_CODE
/* det ==> model_det */
#define mercury__exception__builtin_catch_3_p_0 \
mercury__exception__builtin_catch_model_det
/* semidet ==> model_semi */
#define mercury__exception__builtin_catch_3_p_1 \
mercury__exception__builtin_catch_model_semi
/* cc_multi ==> model_det */
#define mercury__exception__builtin_catch_3_p_2 \
mercury__exception__builtin_catch_model_det
/* cc_nondet ==> model_semi */
#define mercury__exception__builtin_catch_3_p_3 \
mercury__exception__builtin_catch_model_semi
/* multi ==> model_non */
#define mercury__exception__builtin_catch_3_p_4 \
mercury__exception__builtin_catch_model_non
/* nondet ==> model_non */
#define mercury__exception__builtin_catch_3_p_5 \
mercury__exception__builtin_catch_model_non
void mercury__exception__builtin_throw_1_p_0(MR_Word);
void mercury__exception__builtin_throw_1_p_0(MR_Word exception);
void mercury__exception__builtin_catch_model_det(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output);
bool mercury__exception__builtin_catch_model_semi(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output);
void mercury__exception__builtin_catch_model_non(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output,
#ifdef MR_USE_GCC_NESTED_FUNCTIONS
MR_NestedCont cont
#else
MR_Cont cont, void *cont_env
#endif
);
#endif /* MR_HIGHLEVEL_CODE */
").
:- pragma c_code("
#ifdef MR_HIGHLEVEL_CODE
/*---------------------------------------------------------------------------*/
static void
ML_call_goal_det(MR_Word type_info, MR_Word closure, MR_Box *result)
{
typedef void FuncType(void *, MR_Box *);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
(*code)((void *) closure, result);
}
static bool
ML_call_goal_semi(MR_Word type_info, MR_Word closure, MR_Box *result)
{
typedef bool FuncType(void *, MR_Box *);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
return (*code)((void *) closure, result);
}
#ifdef MR_USE_GCC_NESTED_FUNCTIONS
static void
ML_call_goal_non(MR_Word type_info, MR_Word closure, MR_Box *result,
MR_NestedCont cont)
{
typedef void FuncType(void *, MR_Box *, MR_NestedCont);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
(*code)((void *) closure, result, cont);
}
#else
static void
ML_call_goal_non(MR_Word type_info, MR_Word closure, MR_Box *result,
MR_Cont cont, void *cont_env)
{
typedef void FuncType(void *, MR_Box *, MR_Cont, void *);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
(*code)((void *) closure, result, cont, cont_env);
}
#endif
/*---------------------------------------------------------------------------*/
static void
ML_call_handler_det(MR_Word type_info, MR_Word closure, MR_Word exception,
MR_Box *result)
{
typedef void FuncType(void *, MR_Box, MR_Box *);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
(*code)((void *) closure, exception, result);
}
static bool
ML_call_handler_semi(MR_Word type_info, MR_Word closure, MR_Word exception,
MR_Box *result)
{
typedef bool FuncType(void *, MR_Box, MR_Box *);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
return (*code)((void *) closure, exception, result);
}
#ifdef MR_USE_GCC_NESTED_FUNCTIONS
static void
ML_call_handler_non(MR_Word type_info, MR_Word closure, MR_Word exception,
MR_Box *result, MR_NestedCont cont)
{
typedef void FuncType(void *, MR_Box, MR_Box *, MR_NestedCont);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
(*code)((void *) closure, exception, result, cont);
}
#else
static void
ML_call_handler_non(MR_Word type_info, MR_Word closure, MR_Word exception,
MR_Box *result, MR_Cont cont, void *cont_env)
{
typedef void FuncType(void *, MR_Box, MR_Box *, MR_Cont, void *);
FuncType *code = (FuncType *)
MR_field(MR_mktag(0), closure, (Integer) 1);
(*code)((void *) closure, exception, result, cont, cont_env);
}
#endif
/*---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <setjmp.h>
typedef MR_Word MR_Univ;
typedef struct ML_ExceptionHandler_struct {
struct ML_ExceptionHandler_struct *prev;
jmp_buf handler;
MR_Univ exception;
} ML_ExceptionHandler;
ML_ExceptionHandler *ML_exception_handler;
void
mercury__exception__builtin_throw_1_p_0(MR_Univ exception)
{
if (ML_exception_handler->handler == NULL) {
ML_report_uncaught_exception(exception);
abort();
} else {
ML_exception_handler->exception = exception;
longjmp(ML_exception_handler->handler, 1);
}
}
void
mercury__exception__builtin_catch_model_det(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output)
{
ML_ExceptionHandler this_handler;
this_handler.prev = ML_exception_handler;
ML_exception_handler = &this_handler;
if (setjmp(this_handler.handler) == 0) {
ML_call_goal_det(type_info, pred, output);
ML_exception_handler = this_handler.prev;
} else {
ML_exception_handler = this_handler.prev;
ML_call_handler_det(type_info, handler_pred,
this_handler.exception, output);
}
}
bool
mercury__exception__builtin_catch_model_semi(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output)
{
ML_ExceptionHandler this_handler;
this_handler.prev = ML_exception_handler;
ML_exception_handler = &this_handler;
if (setjmp(this_handler.handler) == 0) {
bool result = ML_call_goal_semi(type_info, pred, output);
ML_exception_handler = this_handler.prev;
return result;
} else {
ML_exception_handler = this_handler.prev;
return ML_call_handler_semi(type_info, handler_pred,
this_handler.exception, output);
}
}
#ifdef MR_USE_GCC_NESTED_FUNCTIONS
void
mercury__exception__builtin_catch_model_non(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output,
MR_NestedCont cont)
{
ML_ExceptionHandler this_handler;
auto void success_cont(void);
void success_cont(void) {
/*
** If we reach here, it means that
** the nondet goal has succeeded, so we
** need to restore the previous exception
** handler before calling its continuation
*/
ML_exception_handler = this_handler.prev;
(*cont)();
/*
** If we get here, it means that the continuation
** has failed, and so we are about to redo the
** nondet goal. Thus we need to re-establish
** its exception handler.
*/
ML_exception_handler = &this_handler;
}
this_handler.prev = ML_exception_handler;
ML_exception_handler = &this_handler;
if (setjmp(this_handler.handler) == 0) {
ML_call_goal_non(type_info, pred, output, success_cont);
ML_exception_handler = this_handler.prev;
} else {
ML_exception_handler = this_handler.prev;
ML_call_handler_non(type_info, handler_pred,
this_handler.exception, output, cont);
}
}
#else /* ! MR_USE_GCC_NESTED_FUNCTIONS */
struct ML_catch_env {
ML_ExceptionHandler this_handler;
MR_Cont cont;
void *cont_env;
};
static void
ML_catch_success_cont(void *env_ptr) {
struct ML_catch_env *env = (struct ML_catch_env *) env_ptr;
/*
** If we reach here, it means that
** the nondet goal has succeeded, so we
** need to restore the previous exception
** handler before calling its continuation
*/
ML_exception_handler = env->this_handler.prev;
(*env->cont)(env->cont_env);
/*
** If we get here, it means that the continuation
** has failed, and so we are about to redo the
** nondet goal. Thus we need to re-establish
** its exception handler.
*/
ML_exception_handler = &env->this_handler;
}
void
mercury__exception__builtin_catch_model_non(MR_Word type_info,
MR_Word pred, MR_Word handler_pred, MR_Box *output,
MR_Cont cont, void *cont_env)
{
struct ML_catch_env locals;
locals.cont = cont;
locals.cont_env = cont_env;
locals.this_handler.prev = ML_exception_handler;
ML_exception_handler = &locals.this_handler;
if (setjmp(locals.this_handler.handler) == 0) {
ML_call_goal_non(type_info, pred, output,
ML_catch_success_cont, &locals);
/*
** If we reach here, it means that
** the nondet goal has failed, so we
** need to restore the previous exception
** handler
*/
ML_exception_handler = locals.this_handler.prev;
return;
} else {
/*
** We caught an exception.
** Restore the previous exception handler,
** and then invoke the handler predicate
** for this handler.
*/
ML_exception_handler = locals.this_handler.prev;
ML_call_handler_non(type_info, handler_pred,
locals.this_handler.exception, output,
cont, cont_env);
}
}
#endif /* ! MR_USE_GCC_NESTED_FUNCTIONS */
#endif /* MR_HIGHLEVEL_CODE */
").
/*********
This causes problems because the LLDS back-end
does not let you export code with determinism `nondet'.
Instead we handle-code it... see below.
:- pred call_goal(pred(T), T).
:- mode call_goal(pred(out) is det, out) is det.
:- mode call_goal(pred(out) is semidet, out) is semidet.
:- mode call_goal(pred(out) is nondet, out) is nondet.
call_goal(Goal, Result) :- Goal(Result).
:- pred call_handler(pred(univ, T), univ, T).
:- mode call_handler(pred(in, out) is det, in, out) is det.
:- mode call_handler(pred(in, out) is semidet, in, out) is semidet.
:- mode call_handler(pred(in, out) is nondet, in, out) is nondet.
call_handler(Handler, Exception, Result) :- Handler(Exception, Result).
:- pragma export(call_goal(pred(out) is det, out), "ML_call_goal_det").
:- pragma export(call_goal(pred(out) is semidet, out), "ML_call_goal_semidet").
% :- pragma export(call_goal(pred(out) is nondet, out), "ML_call_goal_nondet").
:- pragma export(call_handler(pred(in, out) is det, in, out),
"ML_call_handler_det").
:- pragma export(call_handler(pred(in, out) is semidet, in, out),
"ML_call_handler_semidet").
% :- pragma export(call_handler(pred(in, out) is nondet, in, out),
% "ML_call_handler_nondet").
*******/
%-----------------------------------------------------------------------------%
%
% The --no-high-level-code implementation
%
:- pragma c_header_code("
#ifndef MR_HIGHLEVEL_CODE
#include <assert.h>
#include <stdio.h>
#include ""mercury_deep_copy.h""
@@ -459,9 +818,11 @@ wrap_exception(Exception, exception(Exception)).
MR_DECLARE_TYPE_CTOR_INFO_STRUCT( \
mercury_data_std_util__type_ctor_info_univ_0);
#endif
").
:- pragma c_code("
#ifndef MR_HIGHLEVEL_CODE
/*
** MR_trace_throw():
@@ -1076,6 +1437,8 @@ void mercury_sys_init_exceptions(void) {
exceptions_module();
}
#endif /* ! MR_HIGHLEVEL_CODE */
").
%-----------------------------------------------------------------------------%

View File

@@ -40,10 +40,12 @@ garbage_collect -->
:- pragma c_code(garbage_collect, [will_not_call_mercury], "
#ifdef CONSERVATIVE_GC
#ifndef MR_HIGHLEVEL_CODE
/* clear out the stacks and registers before garbage collecting */
MR_clear_zone_for_GC(MR_CONTEXT(detstack_zone), MR_sp + 1);
MR_clear_zone_for_GC(MR_CONTEXT(nondetstack_zone), MR_maxfr + 1);
MR_clear_regs_for_GC();
#endif
GC_gcollect();
#endif

View File

@@ -227,7 +227,9 @@
""Software error: Domain error in call to `%s'\\n"",
where);
MR_trace_report(stderr);
#ifndef MR_HIGHLEVEL_CODE
MR_dump_stack(MR_succip, MR_sp, MR_curfr, FALSE);
#endif
exit(1);
}