mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-23 21:33:49 +00:00
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.
88 lines
3.3 KiB
Mathematica
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
|
|
").
|
|
|