Files
mercury/extras/references/nb_reference.m
Warwick Harvey 9cbccbd5dc This change adds a new extras directory, "references".
Estimated hours taken: 70 (plus whatever pets spent when he wrote the
original version of this)

This change adds a new extras directory, "references".  This directory
contains two impure reference type modules and a module that allows scoped
non-backtrackable update, along with examples of using them and tests.
These modules are intended to be useful when HAL is retargetted to Mercury,
for implementing global variables (backtracking and non-backtracking), and
may also be useful for the debugger.

In order to implement these features, a new memory zone "global heap" was
added to the runtime system, for a heap which is not reclaimed on failure,
along with a pair of functions for copying terms to this heap.

runtime/mercury_deep_copy.c:
runtime/mercury_deep_copy.h:
	Added two functions, MR_make_permanent() and
	MR_make_partially_permanent(), which essentially do a deep copy of a
	term to the global heap.
	(In conservative GC grades, these functions actually do nothing).

runtime/mercury_engine.c:
runtime/mercury_engine.h:
	Added fields global_heap_zone and e_global_hp (for the global heap
	and its heap pointer) to the MR_mercury_engine_struct, along with
	appropriate initialisation, etc.
	Defined MR_heap_zone, MR_solutions_heap_zone, and
	MR_global_heap_zone for convenient access to the corresponding field
	of the relevant Mercury engine.

runtime/mercury_memory.c:
	Added code for handling the size and zone size of the global heap.

runtime/mercury_regorder.h:
runtime/mercury_regs.h:
	Defined MR_global_hp (the global heap pointer for general use),
	along with corresponding other changes.

runtime/mercury_wrapper.c:
runtime/mercury_wrapper.h:
	Added declarations and initialisation of the size and zone_size of
	the global_heap.
	Added an entry for MR_GLOBAL_HP_RN to print_register_usage_counts()
	(plus missing entries for MR_SOL_HP_RN, MR_MIN_HP_REC and
	MR_MIN_SOL_HP_REC).

New files:

extras/references/Mmakefile:
	Mmakefile for building and testing these modules.

extras/references/README:
	Description of contents of this directory.

extras/references/global.m:
	A wrapper module for building a library containing the nb_reference,
	reference and scoped_update modules.

extras/references/nb_reference.m:
	Implements references which are not backtracked on failure.

extras/references/reference.m:
	Implements references which *are* backtracked on failure.

extras/references/scoped_update.m:
	Allows nested scoping of non-backtracking references.

extras/references/samples/Mmakefile:
extras/references/samples/max_of.m:
extras/references/samples/max_test.exp:
extras/references/samples/max_test.m:
	An example of using a non-backtracking reference (to find the
	maximum of the solutions generated by a predicate), with tests.

extras/references/tests/Mmakefile:
extras/references/tests/ref_test.exp:
extras/references/tests/ref_test.m:
	Some tests of references (backtracking and non-backtracking) and
	scoping.
1998-06-18 04:30:48 +00:00

88 lines
3.3 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1998 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.
%-----------------------------------------------------------------------------%
%
% File : nb_reference.m
% Authors : pets (Peter Schachte)
% Stability : low
% Purpose : A non-backtrackably modifiable storage type
%
% This module provides impure code for manipulating a non-backtrackable
% reference type. The basic idea is that you allocate a reference and pass
% it through your code, and each time you dereference it you get the value
% most recently assigned to it, even if the assignment has been backtracked
% over. This gives you a way to communicate information between disjunctive
% alternatives in your code.
%
% Because assignments to nb_references need to survive backtracking, every
% term assigned to a nb_reference must be fully copied in some compiler
% grades. This means that nb_references may be somewhat expensive to use for
% large terms. However, dereferencing an nb_reference does not need to copy
% the term, so it is very efficient. Furthermore, if (part of) a new value
% being assigned to a nb_reference was itself (part of) an nb_reference, that
% part will not need to be copied. For example, if you use nb_references to
% build up a long list of terms one at a time, each time you add a new term
% to the list it will need to be copied, but the old value will have already
% been copied so it will not need to be copied again.
%
% One further issue arises due to the copying of terms. Because copied terms
% are not reclaimed on failure, the only way they can be reclaimed is through
% garbage collection. If you use nb_references in a grade without garbage
% collection, they will never be reclaimed.
:- module nb_reference.
:- interface.
% A non-backtrackably destructively modifiable reference type
:- type nb_reference(T).
% Create a new nb_reference given a term for it to reference.
:- impure pred new_nb_reference(T::in, nb_reference(T)::out) is det.
% Get the value currently referred to by a nb_reference.
:- semipure pred value(nb_reference(T)::in, T::out) is det.
% (non-backtrackably) modify a nb_reference to refer to a new object.
:- impure pred update(nb_reference(T)::in, T::in) is det.
:- implementation.
% This type is implemented in C.
:- type nb_reference(T) ---> nb_reference(c_pointer).
:- pragma c_header_code("#include ""mercury_deep_copy.h""").
:- pragma inline(new_nb_reference/2).
:- pragma c_code(new_nb_reference(X::in, Ref::out), will_not_call_mercury, "
incr_hp(Ref, 1);
#ifndef CONSERVATIVE_GC
save_transient_registers();
#endif
*(Word *) Ref = MR_make_long_lived(X, (Word *) TypeInfo_for_T,
(Word *) Ref);
#ifndef CONSERVATIVE_GC
restore_transient_registers();
#endif
").
:- pragma inline(value/2).
:- pragma c_code(value(Ref::in, X::out), will_not_call_mercury, "
X = *(Word *) Ref;
").
:- pragma inline(update/2).
:- pragma c_code(update(Ref::in, X::in), will_not_call_mercury, "
#ifndef CONSERVATIVE_GC
save_transient_registers();
#endif
*(Word *) Ref = MR_make_long_lived(X, (Word *) TypeInfo_for_T,
(Word *) Ref);
#ifndef CONSERVATIVE_GC
restore_transient_registers();
#endif
").