mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-25 06:50:46 -08:00
Update html.
Copied from Perforce Change: 180468 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
5e9f42cd44
commit
bd034b6eb0
21 changed files with 966 additions and 258 deletions
|
|
@ -1,6 +1,6 @@
|
|||
/* scheme.c -- SCHEME INTERPRETER EXAMPLE FOR THE MEMORY POOL SYSTEM
|
||||
*
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2012-10-09/user-guide/example/scheme/scheme-advanced.c#17 $
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2012-10-09/user-guide/example/scheme/scheme-advanced.c#21 $
|
||||
* Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This is a toy interpreter for a subset of the Scheme programming
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
* SCHEME TO DO LIST
|
||||
* - unbounded integers, other number types.
|
||||
* - do, named let.
|
||||
* - named let.
|
||||
* - quasiquote: vectors; nested; dotted.
|
||||
* - Lots of library.
|
||||
* - \#foo unsatisfactory in read and print
|
||||
|
|
@ -1919,10 +1919,85 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* entry_do -- (do ((<var> <init> <step1>) ...) (<test> <exp> ...) <command> ...) */
|
||||
|
||||
/* entry_do -- (do ((<var> <init> <step1>) ...) (<test> <exp> ...) <command> ...)
|
||||
* Do is an iteration construct. It specifies a set of variables to be
|
||||
* bound, how they are to be initialized at the start, and how they
|
||||
* are to be updated on each iteration. When a termination condition
|
||||
* is met, the loop exits with a specified result value.
|
||||
* See R4RS 4.2.4.
|
||||
*/
|
||||
static obj_t entry_do(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t inner_env, next_env, bindings;
|
||||
unless(TYPE(operands) == TYPE_PAIR &&
|
||||
TYPE(CDR(operands)) == TYPE_PAIR &&
|
||||
TYPE(CADR(operands)) == TYPE_PAIR)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
inner_env = make_pair(obj_empty, env);
|
||||
|
||||
/* Do expressions are evaluated as follows: The <init> expressions
|
||||
are evaluated (in some unspecified order), the <variable>s are
|
||||
bound to fresh locations, the results of the <init> expressions
|
||||
are stored in the bindings of the <variable>s, and then the
|
||||
iteration phase begins. */
|
||||
bindings = CAR(operands);
|
||||
while(TYPE(bindings) == TYPE_PAIR) {
|
||||
obj_t binding = CAR(bindings);
|
||||
unless(TYPE(binding) == TYPE_PAIR &&
|
||||
TYPE(CAR(binding)) == TYPE_SYMBOL &&
|
||||
TYPE(CDR(binding)) == TYPE_PAIR &&
|
||||
(CDDR(binding) == obj_empty ||
|
||||
(TYPE(CDDR(binding)) == TYPE_PAIR &&
|
||||
CDDDR(binding) == obj_empty)))
|
||||
error("%s: illegal binding", operator->operator.name);
|
||||
define(inner_env, CAR(binding), eval(env, op_env, CADR(binding)));
|
||||
bindings = CDR(bindings);
|
||||
}
|
||||
for(;;) {
|
||||
/* Each iteration begins by evaluating <test>; */
|
||||
obj_t test = CADR(operands);
|
||||
if(eval(inner_env, op_env, CAR(test)) == obj_false) {
|
||||
/* if the result is false (see section see section 6.1
|
||||
Booleans), then the <command> expressions are evaluated in
|
||||
order for effect, */
|
||||
obj_t commands = CDDR(operands);
|
||||
while(TYPE(commands) == TYPE_PAIR) {
|
||||
eval(inner_env, op_env, CAR(commands));
|
||||
commands = CDR(commands);
|
||||
}
|
||||
unless(commands == obj_empty)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
|
||||
/* the <step> expressions are evaluated in some unspecified
|
||||
order, the <variable>s are bound to fresh locations, the
|
||||
results of the <step>s are stored in the bindings of the
|
||||
<variable>s, and the next iteration begins. */
|
||||
bindings = CAR(operands);
|
||||
next_env = make_pair(obj_empty, inner_env);
|
||||
while(TYPE(bindings) == TYPE_PAIR) {
|
||||
obj_t binding = CAR(bindings);
|
||||
unless(CDDR(binding) == obj_empty)
|
||||
define(next_env, CAR(binding), eval(inner_env, op_env, CADDR(binding)));
|
||||
bindings = CDR(bindings);
|
||||
}
|
||||
inner_env = next_env;
|
||||
} else {
|
||||
/* If <test> evaluates to a true value, then the <expression>s
|
||||
are evaluated from left to right and the value of the last
|
||||
<expression> is returned as the value of the do expression.
|
||||
If no <expression>s are present, then the value of the do
|
||||
expression is unspecified. */
|
||||
obj_t result = obj_undefined;
|
||||
test = CDR(test);
|
||||
while(TYPE(test) == TYPE_PAIR) {
|
||||
result = eval(inner_env, op_env, CAR(test));
|
||||
test = CDR(test);
|
||||
}
|
||||
unless(test == obj_empty)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
error("%s: unimplemented", operator->operator.name);
|
||||
return obj_error;
|
||||
}
|
||||
|
|
@ -2087,11 +2162,10 @@ static obj_t entry_begin(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
/* BUILT-IN FUNCTIONS */
|
||||
|
||||
|
||||
/* entry_not -- (not <obj>)
|
||||
*
|
||||
* Not returns #t if obj is false, and return #f otherwise. R4RS 6.1.
|
||||
/* (not <obj>)
|
||||
* Not returns #t if obj is false, and return #f otherwise.
|
||||
* See R4RS 6.1.
|
||||
*/
|
||||
|
||||
static obj_t entry_not(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2100,11 +2174,10 @@ static obj_t entry_not(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_booleanp -- (boolean? <obj>)
|
||||
*
|
||||
* Boolean? return #t if obj is either #t or #f, and #f otherwise. R4RS 6.1.
|
||||
/* (boolean? <obj>)
|
||||
* Boolean? return #t if obj is either #t or #f, and #f otherwise.
|
||||
* See R4RS 6.1.
|
||||
*/
|
||||
|
||||
static obj_t entry_booleanp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2113,8 +2186,11 @@ static obj_t entry_booleanp(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* entry_eqvp -- (eqv? <obj1> <obj2>) */
|
||||
|
||||
/* (eqv? <obj1> <obj2>)
|
||||
* The eqv? procedure defines a useful equivalence relation on
|
||||
* objects.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_eqvp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -2123,8 +2199,11 @@ static obj_t entry_eqvp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_eqp -- (eq? <obj1> <obj2>) */
|
||||
|
||||
/* (eq? <obj1> <obj2>)
|
||||
* Eq? is similar to eqv? except that in some cases it is capable of
|
||||
* discerning distinctions finer than those detectable by eqv?.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_eqp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -2133,8 +2212,6 @@ static obj_t entry_eqp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_equalp -- (equal? <obj1> <obj2>) */
|
||||
|
||||
static int equalp(obj_t obj1, obj_t obj2)
|
||||
{
|
||||
size_t i;
|
||||
|
|
@ -2159,6 +2236,14 @@ static int equalp(obj_t obj1, obj_t obj2)
|
|||
}
|
||||
}
|
||||
|
||||
/* (equal? <obj1> <obj2>)
|
||||
* Equal? recursively compares the contents of pairs, vectors, and
|
||||
* strings, applying eqv? on other objects such as numbers and
|
||||
* symbols. A rule of thumb is that objects are generally equal? if
|
||||
* they print the same. Equal? may fail to terminate if its arguments
|
||||
* are circular data structures.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_equalp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -2167,8 +2252,10 @@ static obj_t entry_equalp(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* entry_pairp -- (pair? <obj>) */
|
||||
|
||||
/* (pair? <obj>)
|
||||
* Pair? returns #t if obj is a pair, and otherwise returns #f.
|
||||
* See R4RS 6.3.
|
||||
*/
|
||||
static obj_t entry_pairp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2311,6 +2398,11 @@ static obj_t entry_length(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (append list ...)
|
||||
* Returns a list consisting of the elements of the first list
|
||||
* followed by the elements of the other lists.
|
||||
* See R4RS 6.3.
|
||||
*/
|
||||
static obj_t entry_append(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2, result, pair, end;
|
||||
|
|
@ -2334,6 +2426,12 @@ static obj_t entry_append(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (integer? obj)
|
||||
* These numerical type predicates can be applied to any kind of
|
||||
* argument, including non-numbers. They return #t if the object is of
|
||||
* the named type, and otherwise they return #f.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_integerp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2430,6 +2528,10 @@ static obj_t entry_apply(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
}
|
||||
|
||||
|
||||
/* (+ z1 ...)
|
||||
* This procedure returns the sum of its arguments.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_add(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t args;
|
||||
|
|
@ -2447,6 +2549,10 @@ static obj_t entry_add(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* (* z1 ...)
|
||||
* This procedure returns the product of its arguments.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_multiply(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t args;
|
||||
|
|
@ -2464,6 +2570,14 @@ static obj_t entry_multiply(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (- z)
|
||||
* (- z1 z2)
|
||||
* (- z1 z2 ...)
|
||||
* With two or more arguments, this procedure returns the difference
|
||||
* of its arguments, associating to the left. With one argument,
|
||||
* however, it returns the additive inverse of its argument.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_subtract(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2487,6 +2601,14 @@ static obj_t entry_subtract(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (/ z)
|
||||
* (/ z1 z2)
|
||||
* (/ z1 z2 ...)
|
||||
* With two or more arguments, this procedure returns the quotient
|
||||
* of its arguments, associating to the left. With one argument,
|
||||
* however, it returns the multiplicative inverse of its argument.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2514,6 +2636,11 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (< x1 x2 x3 ...)
|
||||
* This procedure returns #t if its arguments are monotonically
|
||||
* increasing.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_lessthan(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2535,6 +2662,11 @@ static obj_t entry_lessthan(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (> x1 x2 x3 ...)
|
||||
* This procedure returns #t if its arguments are monotonically
|
||||
* decreasing.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_greaterthan(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2777,8 +2909,15 @@ static obj_t entry_load(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* TODO: This doesn't work if the promise refers to its own value. */
|
||||
|
||||
/* (force promise)
|
||||
* Forces the value of promise. If no value has been computed for the
|
||||
* promise, then a value is computed and returned. The value of the
|
||||
* promise is cached (or "memoized") so that if it is forced a second
|
||||
* time, the previously computed value is returned.
|
||||
* See R4RS 6.9.
|
||||
*
|
||||
* TODO: This doesn't work if the promise refers to its own value.
|
||||
*/
|
||||
static obj_t entry_force(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t promise;
|
||||
|
|
@ -2842,6 +2981,10 @@ static obj_t entry_integer_to_char(obj_t env, obj_t op_env, obj_t operator, obj_
|
|||
}
|
||||
|
||||
|
||||
/* (vector? obj)
|
||||
* Returns #t if obj is a vector, otherwise returns #f.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vectorp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2850,6 +2993,13 @@ static obj_t entry_vectorp(obj_t env, obj_t op_env, obj_t operator, obj_t operan
|
|||
}
|
||||
|
||||
|
||||
/* (make-vector k)
|
||||
* (make-vector k fill)
|
||||
* Returns a newly allocated vector of k elements. If a second
|
||||
* argument is given, then each element is initialized to fill.
|
||||
* Otherwise the initial contents of each element is unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_make_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t length, rest, fill = obj_undefined;
|
||||
|
|
@ -2865,6 +3015,11 @@ static obj_t entry_make_vector(obj_t env, obj_t op_env, obj_t operator, obj_t op
|
|||
}
|
||||
|
||||
|
||||
/* (vector obj ...)
|
||||
* Returns a newly allocated vector whose elements contain the given
|
||||
* arguments. Analogous to list.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t rest, vector;
|
||||
|
|
@ -2875,6 +3030,10 @@ static obj_t entry_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (vector-length vector)
|
||||
* Returns the number of elements in vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_length(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector;
|
||||
|
|
@ -2885,6 +3044,11 @@ static obj_t entry_vector_length(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (vector-ref vector k)
|
||||
* k must be a valid index of vector. Vector-ref returns the contents
|
||||
* of element k of vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_ref(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, index;
|
||||
|
|
@ -2900,6 +3064,12 @@ static obj_t entry_vector_ref(obj_t env, obj_t op_env, obj_t operator, obj_t ope
|
|||
}
|
||||
|
||||
|
||||
/* (vector-set! vector k obj
|
||||
* k must be a valid index of vector. Vector-set! stores obj in
|
||||
* element k of vector. The value returned by vector-set! is
|
||||
* unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_set(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, index, obj;
|
||||
|
|
@ -2916,6 +3086,11 @@ static obj_t entry_vector_set(obj_t env, obj_t op_env, obj_t operator, obj_t ope
|
|||
}
|
||||
|
||||
|
||||
/* (vector->list vector)
|
||||
* Vector->list returns a newly allocated list of the objects
|
||||
* contained in the elements of vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_to_list(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, list;
|
||||
|
|
@ -2933,6 +3108,11 @@ static obj_t entry_vector_to_list(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (list->vector list)
|
||||
* List->vector returns a newly created vector initialized to the
|
||||
* elements of the list list.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_list_to_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t list, vector;
|
||||
|
|
@ -2944,6 +3124,11 @@ static obj_t entry_list_to_vector(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (vector-fill! vector fill)
|
||||
* Stores fill in every element of vector. The value returned by
|
||||
* vector-fill! is unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_fill(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, obj;
|
||||
|
|
@ -2976,6 +3161,10 @@ static obj_t entry_error(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
}
|
||||
|
||||
|
||||
/* (symbol->string symbol)
|
||||
* Returns the name of symbol as a string.
|
||||
* See R4RS 6.4.
|
||||
*/
|
||||
static obj_t entry_symbol_to_string(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t symbol;
|
||||
|
|
@ -2986,6 +3175,10 @@ static obj_t entry_symbol_to_string(obj_t env, obj_t op_env, obj_t operator, obj
|
|||
}
|
||||
|
||||
|
||||
/* (string->symbol symbol)
|
||||
* Returns the symbol whose name is string.
|
||||
* See R4RS 6.4.
|
||||
*/
|
||||
static obj_t entry_string_to_symbol(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t string;
|
||||
|
|
@ -4266,8 +4459,9 @@ static void *start(void *p, size_t s)
|
|||
*/
|
||||
|
||||
static mps_gen_param_s obj_gen_params[] = {
|
||||
{ 150, 0.85 },
|
||||
{ 170, 0.45 }
|
||||
{ 6400, 0.80 },
|
||||
{ 6400, 0.80 },
|
||||
{ 6400, 0.80 }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -4288,7 +4482,7 @@ int main(int argc, char *argv[])
|
|||
It holds all the MPS "global" state and is where everything happens. */
|
||||
res = mps_arena_create(&arena,
|
||||
mps_arena_class_vm(),
|
||||
(size_t)(32 * 1024 * 1024));
|
||||
(size_t)(32ul * 1024 * 1024));
|
||||
if (res != MPS_RES_OK) error("Couldn't create arena");
|
||||
|
||||
/* Create the object format. */
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
/* scheme.c -- SCHEME INTERPRETER EXAMPLE FOR THE MEMORY POOL SYSTEM
|
||||
*
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2012-10-09/user-guide/example/scheme/scheme-malloc.c#18 $
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2012-10-09/user-guide/example/scheme/scheme-malloc.c#20 $
|
||||
* Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* TO DO
|
||||
* - unbounded integers, other number types.
|
||||
* - do, named let.
|
||||
* - named let.
|
||||
* - quasiquote: vectors; nested; dotted.
|
||||
* - Lots of library.
|
||||
* - \#foo unsatisfactory in read and print
|
||||
|
|
@ -1649,10 +1649,85 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* entry_do -- (do ((<var> <init> <step1>) ...) (<test> <exp> ...) <command> ...) */
|
||||
|
||||
/* entry_do -- (do ((<var> <init> <step1>) ...) (<test> <exp> ...) <command> ...)
|
||||
* Do is an iteration construct. It specifies a set of variables to be
|
||||
* bound, how they are to be initialized at the start, and how they
|
||||
* are to be updated on each iteration. When a termination condition
|
||||
* is met, the loop exits with a specified result value.
|
||||
* See R4RS 4.2.4.
|
||||
*/
|
||||
static obj_t entry_do(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t inner_env, next_env, bindings;
|
||||
unless(TYPE(operands) == TYPE_PAIR &&
|
||||
TYPE(CDR(operands)) == TYPE_PAIR &&
|
||||
TYPE(CADR(operands)) == TYPE_PAIR)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
inner_env = make_pair(obj_empty, env);
|
||||
|
||||
/* Do expressions are evaluated as follows: The <init> expressions
|
||||
are evaluated (in some unspecified order), the <variable>s are
|
||||
bound to fresh locations, the results of the <init> expressions
|
||||
are stored in the bindings of the <variable>s, and then the
|
||||
iteration phase begins. */
|
||||
bindings = CAR(operands);
|
||||
while(TYPE(bindings) == TYPE_PAIR) {
|
||||
obj_t binding = CAR(bindings);
|
||||
unless(TYPE(binding) == TYPE_PAIR &&
|
||||
TYPE(CAR(binding)) == TYPE_SYMBOL &&
|
||||
TYPE(CDR(binding)) == TYPE_PAIR &&
|
||||
(CDDR(binding) == obj_empty ||
|
||||
(TYPE(CDDR(binding)) == TYPE_PAIR &&
|
||||
CDDDR(binding) == obj_empty)))
|
||||
error("%s: illegal binding", operator->operator.name);
|
||||
define(inner_env, CAR(binding), eval(env, op_env, CADR(binding)));
|
||||
bindings = CDR(bindings);
|
||||
}
|
||||
for(;;) {
|
||||
/* Each iteration begins by evaluating <test>; */
|
||||
obj_t test = CADR(operands);
|
||||
if(eval(inner_env, op_env, CAR(test)) == obj_false) {
|
||||
/* if the result is false (see section see section 6.1
|
||||
Booleans), then the <command> expressions are evaluated in
|
||||
order for effect, */
|
||||
obj_t commands = CDDR(operands);
|
||||
while(TYPE(commands) == TYPE_PAIR) {
|
||||
eval(inner_env, op_env, CAR(commands));
|
||||
commands = CDR(commands);
|
||||
}
|
||||
unless(commands == obj_empty)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
|
||||
/* the <step> expressions are evaluated in some unspecified
|
||||
order, the <variable>s are bound to fresh locations, the
|
||||
results of the <step>s are stored in the bindings of the
|
||||
<variable>s, and the next iteration begins. */
|
||||
bindings = CAR(operands);
|
||||
next_env = make_pair(obj_empty, inner_env);
|
||||
while(TYPE(bindings) == TYPE_PAIR) {
|
||||
obj_t binding = CAR(bindings);
|
||||
unless(CDDR(binding) == obj_empty)
|
||||
define(next_env, CAR(binding), eval(inner_env, op_env, CADDR(binding)));
|
||||
bindings = CDR(bindings);
|
||||
}
|
||||
inner_env = next_env;
|
||||
} else {
|
||||
/* If <test> evaluates to a true value, then the <expression>s
|
||||
are evaluated from left to right and the value of the last
|
||||
<expression> is returned as the value of the do expression.
|
||||
If no <expression>s are present, then the value of the do
|
||||
expression is unspecified. */
|
||||
obj_t result = obj_undefined;
|
||||
test = CDR(test);
|
||||
while(TYPE(test) == TYPE_PAIR) {
|
||||
result = eval(inner_env, op_env, CAR(test));
|
||||
test = CDR(test);
|
||||
}
|
||||
unless(test == obj_empty)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
error("%s: unimplemented", operator->operator.name);
|
||||
return obj_error;
|
||||
}
|
||||
|
|
@ -1817,11 +1892,10 @@ static obj_t entry_begin(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
/* BUILT-IN FUNCTIONS */
|
||||
|
||||
|
||||
/* entry_not -- (not <obj>)
|
||||
*
|
||||
* Not returns #t if obj is false, and return #f otherwise. R4RS 6.1.
|
||||
/* (not <obj>)
|
||||
* Not returns #t if obj is false, and return #f otherwise.
|
||||
* See R4RS 6.1.
|
||||
*/
|
||||
|
||||
static obj_t entry_not(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -1830,11 +1904,10 @@ static obj_t entry_not(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_booleanp -- (boolean? <obj>)
|
||||
*
|
||||
* Boolean? return #t if obj is either #t or #f, and #f otherwise. R4RS 6.1.
|
||||
/* (boolean? <obj>)
|
||||
* Boolean? return #t if obj is either #t or #f, and #f otherwise.
|
||||
* See R4RS 6.1.
|
||||
*/
|
||||
|
||||
static obj_t entry_booleanp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -1843,8 +1916,11 @@ static obj_t entry_booleanp(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* entry_eqvp -- (eqv? <obj1> <obj2>) */
|
||||
|
||||
/* (eqv? <obj1> <obj2>)
|
||||
* The eqv? procedure defines a useful equivalence relation on
|
||||
* objects.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_eqvp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -1853,8 +1929,11 @@ static obj_t entry_eqvp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_eqp -- (eq? <obj1> <obj2>) */
|
||||
|
||||
/* (eq? <obj1> <obj2>)
|
||||
* Eq? is similar to eqv? except that in some cases it is capable of
|
||||
* discerning distinctions finer than those detectable by eqv?.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_eqp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -1863,8 +1942,6 @@ static obj_t entry_eqp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_equalp -- (equal? <obj1> <obj2>) */
|
||||
|
||||
static int equalp(obj_t obj1, obj_t obj2)
|
||||
{
|
||||
size_t i;
|
||||
|
|
@ -1889,6 +1966,14 @@ static int equalp(obj_t obj1, obj_t obj2)
|
|||
}
|
||||
}
|
||||
|
||||
/* (equal? <obj1> <obj2>)
|
||||
* Equal? recursively compares the contents of pairs, vectors, and
|
||||
* strings, applying eqv? on other objects such as numbers and
|
||||
* symbols. A rule of thumb is that objects are generally equal? if
|
||||
* they print the same. Equal? may fail to terminate if its arguments
|
||||
* are circular data structures.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_equalp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -1897,8 +1982,10 @@ static obj_t entry_equalp(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* entry_pairp -- (pair? <obj>) */
|
||||
|
||||
/* (pair? <obj>)
|
||||
* Pair? returns #t if obj is a pair, and otherwise returns #f.
|
||||
* See R4RS 6.3.
|
||||
*/
|
||||
static obj_t entry_pairp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2041,6 +2128,11 @@ static obj_t entry_length(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (append list ...)
|
||||
* Returns a list consisting of the elements of the first list
|
||||
* followed by the elements of the other lists.
|
||||
* See R4RS 6.3.
|
||||
*/
|
||||
static obj_t entry_append(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2, result, pair, end;
|
||||
|
|
@ -2064,6 +2156,12 @@ static obj_t entry_append(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (integer? obj)
|
||||
* These numerical type predicates can be applied to any kind of
|
||||
* argument, including non-numbers. They return #t if the object is of
|
||||
* the named type, and otherwise they return #f.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_integerp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2160,6 +2258,10 @@ static obj_t entry_apply(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
}
|
||||
|
||||
|
||||
/* (+ z1 ...)
|
||||
* This procedure returns the sum of its arguments.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_add(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t args;
|
||||
|
|
@ -2177,6 +2279,10 @@ static obj_t entry_add(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* (* z1 ...)
|
||||
* This procedure returns the product of its arguments.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_multiply(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t args;
|
||||
|
|
@ -2194,6 +2300,14 @@ static obj_t entry_multiply(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (- z)
|
||||
* (- z1 z2)
|
||||
* (- z1 z2 ...)
|
||||
* With two or more arguments, this procedure returns the difference
|
||||
* of its arguments, associating to the left. With one argument,
|
||||
* however, it returns the additive inverse of its argument.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_subtract(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2217,6 +2331,14 @@ static obj_t entry_subtract(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (/ z)
|
||||
* (/ z1 z2)
|
||||
* (/ z1 z2 ...)
|
||||
* With two or more arguments, this procedure returns the quotient
|
||||
* of its arguments, associating to the left. With one argument,
|
||||
* however, it returns the multiplicative inverse of its argument.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2244,6 +2366,11 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (< x1 x2 x3 ...)
|
||||
* This procedure returns #t if its arguments are monotonically
|
||||
* increasing.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_lessthan(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2265,6 +2392,11 @@ static obj_t entry_lessthan(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (> x1 x2 x3 ...)
|
||||
* This procedure returns #t if its arguments are monotonically
|
||||
* decreasing.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_greaterthan(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2509,8 +2641,15 @@ static obj_t entry_load(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* TODO: This doesn't work if the promise refers to its own value. */
|
||||
|
||||
/* (force promise)
|
||||
* Forces the value of promise. If no value has been computed for the
|
||||
* promise, then a value is computed and returned. The value of the
|
||||
* promise is cached (or "memoized") so that if it is forced a second
|
||||
* time, the previously computed value is returned.
|
||||
* See R4RS 6.9.
|
||||
*
|
||||
* TODO: This doesn't work if the promise refers to its own value.
|
||||
*/
|
||||
static obj_t entry_force(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t promise;
|
||||
|
|
@ -2574,6 +2713,10 @@ static obj_t entry_integer_to_char(obj_t env, obj_t op_env, obj_t operator, obj_
|
|||
}
|
||||
|
||||
|
||||
/* (vector? obj)
|
||||
* Returns #t if obj is a vector, otherwise returns #f.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vectorp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2582,6 +2725,13 @@ static obj_t entry_vectorp(obj_t env, obj_t op_env, obj_t operator, obj_t operan
|
|||
}
|
||||
|
||||
|
||||
/* (make-vector k)
|
||||
* (make-vector k fill)
|
||||
* Returns a newly allocated vector of k elements. If a second
|
||||
* argument is given, then each element is initialized to fill.
|
||||
* Otherwise the initial contents of each element is unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_make_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t length, rest, fill = obj_undefined;
|
||||
|
|
@ -2597,6 +2747,11 @@ static obj_t entry_make_vector(obj_t env, obj_t op_env, obj_t operator, obj_t op
|
|||
}
|
||||
|
||||
|
||||
/* (vector obj ...)
|
||||
* Returns a newly allocated vector whose elements contain the given
|
||||
* arguments. Analogous to list.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t rest, vector;
|
||||
|
|
@ -2607,6 +2762,10 @@ static obj_t entry_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (vector-length vector)
|
||||
* Returns the number of elements in vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_length(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector;
|
||||
|
|
@ -2617,6 +2776,11 @@ static obj_t entry_vector_length(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (vector-ref vector k)
|
||||
* k must be a valid index of vector. Vector-ref returns the contents
|
||||
* of element k of vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_ref(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, index;
|
||||
|
|
@ -2632,6 +2796,12 @@ static obj_t entry_vector_ref(obj_t env, obj_t op_env, obj_t operator, obj_t ope
|
|||
}
|
||||
|
||||
|
||||
/* (vector-set! vector k obj
|
||||
* k must be a valid index of vector. Vector-set! stores obj in
|
||||
* element k of vector. The value returned by vector-set! is
|
||||
* unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_set(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, index, obj;
|
||||
|
|
@ -2648,6 +2818,11 @@ static obj_t entry_vector_set(obj_t env, obj_t op_env, obj_t operator, obj_t ope
|
|||
}
|
||||
|
||||
|
||||
/* (vector->list vector)
|
||||
* Vector->list returns a newly allocated list of the objects
|
||||
* contained in the elements of vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_to_list(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, list;
|
||||
|
|
@ -2665,6 +2840,11 @@ static obj_t entry_vector_to_list(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (list->vector list)
|
||||
* List->vector returns a newly created vector initialized to the
|
||||
* elements of the list list.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_list_to_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t list, vector;
|
||||
|
|
@ -2676,6 +2856,11 @@ static obj_t entry_list_to_vector(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (vector-fill! vector fill)
|
||||
* Stores fill in every element of vector. The value returned by
|
||||
* vector-fill! is unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_fill(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, obj;
|
||||
|
|
@ -2708,6 +2893,10 @@ static obj_t entry_error(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
}
|
||||
|
||||
|
||||
/* (symbol->string symbol)
|
||||
* Returns the name of symbol as a string.
|
||||
* See R4RS 6.4.
|
||||
*/
|
||||
static obj_t entry_symbol_to_string(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t symbol;
|
||||
|
|
@ -2718,6 +2907,10 @@ static obj_t entry_symbol_to_string(obj_t env, obj_t op_env, obj_t operator, obj
|
|||
}
|
||||
|
||||
|
||||
/* (string->symbol symbol)
|
||||
* Returns the symbol whose name is string.
|
||||
* See R4RS 6.4.
|
||||
*/
|
||||
static obj_t entry_string_to_symbol(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* scheme.c -- SCHEME INTERPRETER EXAMPLE FOR THE MEMORY POOL SYSTEM
|
||||
*
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2012-10-09/user-guide/example/scheme/scheme.c#32 $
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2012-10-09/user-guide/example/scheme/scheme.c#34 $
|
||||
* Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This is a toy interpreter for a subset of the Scheme programming
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
*
|
||||
* SCHEME TO DO LIST
|
||||
* - unbounded integers, other number types.
|
||||
* - do, named let.
|
||||
* - named let.
|
||||
* - quasiquote: vectors; nested; dotted.
|
||||
* - Lots of library.
|
||||
* - \#foo unsatisfactory in read and print
|
||||
|
|
@ -1948,10 +1948,85 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* entry_do -- (do ((<var> <init> <step1>) ...) (<test> <exp> ...) <command> ...) */
|
||||
|
||||
/* entry_do -- (do ((<var> <init> <step1>) ...) (<test> <exp> ...) <command> ...)
|
||||
* Do is an iteration construct. It specifies a set of variables to be
|
||||
* bound, how they are to be initialized at the start, and how they
|
||||
* are to be updated on each iteration. When a termination condition
|
||||
* is met, the loop exits with a specified result value.
|
||||
* See R4RS 4.2.4.
|
||||
*/
|
||||
static obj_t entry_do(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t inner_env, next_env, bindings;
|
||||
unless(TYPE(operands) == TYPE_PAIR &&
|
||||
TYPE(CDR(operands)) == TYPE_PAIR &&
|
||||
TYPE(CADR(operands)) == TYPE_PAIR)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
inner_env = make_pair(obj_empty, env);
|
||||
|
||||
/* Do expressions are evaluated as follows: The <init> expressions
|
||||
are evaluated (in some unspecified order), the <variable>s are
|
||||
bound to fresh locations, the results of the <init> expressions
|
||||
are stored in the bindings of the <variable>s, and then the
|
||||
iteration phase begins. */
|
||||
bindings = CAR(operands);
|
||||
while(TYPE(bindings) == TYPE_PAIR) {
|
||||
obj_t binding = CAR(bindings);
|
||||
unless(TYPE(binding) == TYPE_PAIR &&
|
||||
TYPE(CAR(binding)) == TYPE_SYMBOL &&
|
||||
TYPE(CDR(binding)) == TYPE_PAIR &&
|
||||
(CDDR(binding) == obj_empty ||
|
||||
(TYPE(CDDR(binding)) == TYPE_PAIR &&
|
||||
CDDDR(binding) == obj_empty)))
|
||||
error("%s: illegal binding", operator->operator.name);
|
||||
define(inner_env, CAR(binding), eval(env, op_env, CADR(binding)));
|
||||
bindings = CDR(bindings);
|
||||
}
|
||||
for(;;) {
|
||||
/* Each iteration begins by evaluating <test>; */
|
||||
obj_t test = CADR(operands);
|
||||
if(eval(inner_env, op_env, CAR(test)) == obj_false) {
|
||||
/* if the result is false (see section see section 6.1
|
||||
Booleans), then the <command> expressions are evaluated in
|
||||
order for effect, */
|
||||
obj_t commands = CDDR(operands);
|
||||
while(TYPE(commands) == TYPE_PAIR) {
|
||||
eval(inner_env, op_env, CAR(commands));
|
||||
commands = CDR(commands);
|
||||
}
|
||||
unless(commands == obj_empty)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
|
||||
/* the <step> expressions are evaluated in some unspecified
|
||||
order, the <variable>s are bound to fresh locations, the
|
||||
results of the <step>s are stored in the bindings of the
|
||||
<variable>s, and the next iteration begins. */
|
||||
bindings = CAR(operands);
|
||||
next_env = make_pair(obj_empty, inner_env);
|
||||
while(TYPE(bindings) == TYPE_PAIR) {
|
||||
obj_t binding = CAR(bindings);
|
||||
unless(CDDR(binding) == obj_empty)
|
||||
define(next_env, CAR(binding), eval(inner_env, op_env, CADDR(binding)));
|
||||
bindings = CDR(bindings);
|
||||
}
|
||||
inner_env = next_env;
|
||||
} else {
|
||||
/* If <test> evaluates to a true value, then the <expression>s
|
||||
are evaluated from left to right and the value of the last
|
||||
<expression> is returned as the value of the do expression.
|
||||
If no <expression>s are present, then the value of the do
|
||||
expression is unspecified. */
|
||||
obj_t result = obj_undefined;
|
||||
test = CDR(test);
|
||||
while(TYPE(test) == TYPE_PAIR) {
|
||||
result = eval(inner_env, op_env, CAR(test));
|
||||
test = CDR(test);
|
||||
}
|
||||
unless(test == obj_empty)
|
||||
error("%s: illegal syntax", operator->operator.name);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
error("%s: unimplemented", operator->operator.name);
|
||||
return obj_error;
|
||||
}
|
||||
|
|
@ -2116,11 +2191,10 @@ static obj_t entry_begin(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
/* BUILT-IN FUNCTIONS */
|
||||
|
||||
|
||||
/* entry_not -- (not <obj>)
|
||||
*
|
||||
* Not returns #t if obj is false, and return #f otherwise. R4RS 6.1.
|
||||
/* (not <obj>)
|
||||
* Not returns #t if obj is false, and return #f otherwise.
|
||||
* See R4RS 6.1.
|
||||
*/
|
||||
|
||||
static obj_t entry_not(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2129,11 +2203,10 @@ static obj_t entry_not(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_booleanp -- (boolean? <obj>)
|
||||
*
|
||||
* Boolean? return #t if obj is either #t or #f, and #f otherwise. R4RS 6.1.
|
||||
/* (boolean? <obj>)
|
||||
* Boolean? return #t if obj is either #t or #f, and #f otherwise.
|
||||
* See R4RS 6.1.
|
||||
*/
|
||||
|
||||
static obj_t entry_booleanp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2142,8 +2215,11 @@ static obj_t entry_booleanp(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* entry_eqvp -- (eqv? <obj1> <obj2>) */
|
||||
|
||||
/* (eqv? <obj1> <obj2>)
|
||||
* The eqv? procedure defines a useful equivalence relation on
|
||||
* objects.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_eqvp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -2152,8 +2228,11 @@ static obj_t entry_eqvp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_eqp -- (eq? <obj1> <obj2>) */
|
||||
|
||||
/* (eq? <obj1> <obj2>)
|
||||
* Eq? is similar to eqv? except that in some cases it is capable of
|
||||
* discerning distinctions finer than those detectable by eqv?.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_eqp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -2162,8 +2241,6 @@ static obj_t entry_eqp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* entry_equalp -- (equal? <obj1> <obj2>) */
|
||||
|
||||
static int equalp(obj_t obj1, obj_t obj2)
|
||||
{
|
||||
size_t i;
|
||||
|
|
@ -2188,6 +2265,14 @@ static int equalp(obj_t obj1, obj_t obj2)
|
|||
}
|
||||
}
|
||||
|
||||
/* (equal? <obj1> <obj2>)
|
||||
* Equal? recursively compares the contents of pairs, vectors, and
|
||||
* strings, applying eqv? on other objects such as numbers and
|
||||
* symbols. A rule of thumb is that objects are generally equal? if
|
||||
* they print the same. Equal? may fail to terminate if its arguments
|
||||
* are circular data structures.
|
||||
* See R4RS 6.2.
|
||||
*/
|
||||
static obj_t entry_equalp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2;
|
||||
|
|
@ -2196,8 +2281,10 @@ static obj_t entry_equalp(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* entry_pairp -- (pair? <obj>) */
|
||||
|
||||
/* (pair? <obj>)
|
||||
* Pair? returns #t if obj is a pair, and otherwise returns #f.
|
||||
* See R4RS 6.3.
|
||||
*/
|
||||
static obj_t entry_pairp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2340,6 +2427,11 @@ static obj_t entry_length(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (append list ...)
|
||||
* Returns a list consisting of the elements of the first list
|
||||
* followed by the elements of the other lists.
|
||||
* See R4RS 6.3.
|
||||
*/
|
||||
static obj_t entry_append(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg1, arg2, result, pair, end;
|
||||
|
|
@ -2363,6 +2455,12 @@ static obj_t entry_append(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (integer? obj)
|
||||
* These numerical type predicates can be applied to any kind of
|
||||
* argument, including non-numbers. They return #t if the object is of
|
||||
* the named type, and otherwise they return #f.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_integerp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2459,6 +2557,10 @@ static obj_t entry_apply(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
}
|
||||
|
||||
|
||||
/* (+ z1 ...)
|
||||
* This procedure returns the sum of its arguments.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_add(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t args;
|
||||
|
|
@ -2476,6 +2578,10 @@ static obj_t entry_add(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* (* z1 ...)
|
||||
* This procedure returns the product of its arguments.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_multiply(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t args;
|
||||
|
|
@ -2493,6 +2599,14 @@ static obj_t entry_multiply(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (- z)
|
||||
* (- z1 z2)
|
||||
* (- z1 z2 ...)
|
||||
* With two or more arguments, this procedure returns the difference
|
||||
* of its arguments, associating to the left. With one argument,
|
||||
* however, it returns the additive inverse of its argument.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_subtract(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2516,6 +2630,14 @@ static obj_t entry_subtract(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (/ z)
|
||||
* (/ z1 z2)
|
||||
* (/ z1 z2 ...)
|
||||
* With two or more arguments, this procedure returns the quotient
|
||||
* of its arguments, associating to the left. With one argument,
|
||||
* however, it returns the multiplicative inverse of its argument.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2543,6 +2665,11 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (< x1 x2 x3 ...)
|
||||
* This procedure returns #t if its arguments are monotonically
|
||||
* increasing.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_lessthan(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2564,6 +2691,11 @@ static obj_t entry_lessthan(obj_t env, obj_t op_env, obj_t operator, obj_t opera
|
|||
}
|
||||
|
||||
|
||||
/* (> x1 x2 x3 ...)
|
||||
* This procedure returns #t if its arguments are monotonically
|
||||
* decreasing.
|
||||
* See R4RS 6.5.5.
|
||||
*/
|
||||
static obj_t entry_greaterthan(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg, args;
|
||||
|
|
@ -2805,8 +2937,15 @@ static obj_t entry_load(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
|||
}
|
||||
|
||||
|
||||
/* TODO: This doesn't work if the promise refers to its own value. */
|
||||
|
||||
/* (force promise)
|
||||
* Forces the value of promise. If no value has been computed for the
|
||||
* promise, then a value is computed and returned. The value of the
|
||||
* promise is cached (or "memoized") so that if it is forced a second
|
||||
* time, the previously computed value is returned.
|
||||
* See R4RS 6.9.
|
||||
*
|
||||
* TODO: This doesn't work if the promise refers to its own value.
|
||||
*/
|
||||
static obj_t entry_force(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t promise;
|
||||
|
|
@ -2870,6 +3009,10 @@ static obj_t entry_integer_to_char(obj_t env, obj_t op_env, obj_t operator, obj_
|
|||
}
|
||||
|
||||
|
||||
/* (vector? obj)
|
||||
* Returns #t if obj is a vector, otherwise returns #f.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vectorp(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t arg;
|
||||
|
|
@ -2878,6 +3021,13 @@ static obj_t entry_vectorp(obj_t env, obj_t op_env, obj_t operator, obj_t operan
|
|||
}
|
||||
|
||||
|
||||
/* (make-vector k)
|
||||
* (make-vector k fill)
|
||||
* Returns a newly allocated vector of k elements. If a second
|
||||
* argument is given, then each element is initialized to fill.
|
||||
* Otherwise the initial contents of each element is unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_make_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t length, rest, fill = obj_undefined;
|
||||
|
|
@ -2893,6 +3043,11 @@ static obj_t entry_make_vector(obj_t env, obj_t op_env, obj_t operator, obj_t op
|
|||
}
|
||||
|
||||
|
||||
/* (vector obj ...)
|
||||
* Returns a newly allocated vector whose elements contain the given
|
||||
* arguments. Analogous to list.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t rest, vector;
|
||||
|
|
@ -2903,6 +3058,10 @@ static obj_t entry_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operand
|
|||
}
|
||||
|
||||
|
||||
/* (vector-length vector)
|
||||
* Returns the number of elements in vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_length(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector;
|
||||
|
|
@ -2913,6 +3072,11 @@ static obj_t entry_vector_length(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (vector-ref vector k)
|
||||
* k must be a valid index of vector. Vector-ref returns the contents
|
||||
* of element k of vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_ref(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, index;
|
||||
|
|
@ -2928,6 +3092,12 @@ static obj_t entry_vector_ref(obj_t env, obj_t op_env, obj_t operator, obj_t ope
|
|||
}
|
||||
|
||||
|
||||
/* (vector-set! vector k obj
|
||||
* k must be a valid index of vector. Vector-set! stores obj in
|
||||
* element k of vector. The value returned by vector-set! is
|
||||
* unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_set(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, index, obj;
|
||||
|
|
@ -2944,6 +3114,11 @@ static obj_t entry_vector_set(obj_t env, obj_t op_env, obj_t operator, obj_t ope
|
|||
}
|
||||
|
||||
|
||||
/* (vector->list vector)
|
||||
* Vector->list returns a newly allocated list of the objects
|
||||
* contained in the elements of vector.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_to_list(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, list;
|
||||
|
|
@ -2961,6 +3136,11 @@ static obj_t entry_vector_to_list(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (list->vector list)
|
||||
* List->vector returns a newly created vector initialized to the
|
||||
* elements of the list list.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_list_to_vector(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t list, vector;
|
||||
|
|
@ -2972,6 +3152,11 @@ static obj_t entry_list_to_vector(obj_t env, obj_t op_env, obj_t operator, obj_t
|
|||
}
|
||||
|
||||
|
||||
/* (vector-fill! vector fill)
|
||||
* Stores fill in every element of vector. The value returned by
|
||||
* vector-fill! is unspecified.
|
||||
* See R4RS 6.8.
|
||||
*/
|
||||
static obj_t entry_vector_fill(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t vector, obj;
|
||||
|
|
@ -3004,6 +3189,10 @@ static obj_t entry_error(obj_t env, obj_t op_env, obj_t operator, obj_t operands
|
|||
}
|
||||
|
||||
|
||||
/* (symbol->string symbol)
|
||||
* Returns the name of symbol as a string.
|
||||
* See R4RS 6.4.
|
||||
*/
|
||||
static obj_t entry_symbol_to_string(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t symbol;
|
||||
|
|
@ -3014,6 +3203,10 @@ static obj_t entry_symbol_to_string(obj_t env, obj_t op_env, obj_t operator, obj
|
|||
}
|
||||
|
||||
|
||||
/* (string->symbol symbol)
|
||||
* Returns the symbol whose name is string.
|
||||
* See R4RS 6.4.
|
||||
*/
|
||||
static obj_t entry_string_to_symbol(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
|
||||
{
|
||||
obj_t string;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ delayed. And even if it does die, the space it occupies may not be
|
|||
re-allocated for some time.
|
||||
|
||||
|
||||
.. _guide-debug-advice:
|
||||
|
||||
General debugging advice
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -26,31 +26,55 @@ most of the blocks allocated in that generation should be found to be
|
|||
entirely). If a generation is collected when its blocks are mostly
|
||||
alive, that is a waste of time.
|
||||
|
||||
In the table below I give the execution time of ``test-leaf.scm`` in
|
||||
In the tables below I give the execution time of ``test-leaf.scm`` in
|
||||
the toy Scheme interpreter under different settings for its generation
|
||||
chain. (This test case allocates millions of small short-lived
|
||||
objects.) In each case the AMC pool is given a chain with a single
|
||||
generation with the specified capacity and mortality.
|
||||
chain. (This test case allocates hundreds of millions of small
|
||||
short-lived objects.)
|
||||
|
||||
First, the effect of varying the capacity of a chain with a single
|
||||
generation.
|
||||
|
||||
======== ========= =========================
|
||||
Capacity Mortality Execution time (user+sys)
|
||||
======== ========= =========================
|
||||
100 0.80 39.9
|
||||
200 0.80 30.2
|
||||
400 0.80 25.5
|
||||
800 0.80 16.3
|
||||
1600 0.80 9.0
|
||||
3200 0.80 5.8
|
||||
6400 0.20 4.2
|
||||
6400 0.40 4.1
|
||||
6400 0.60 4.1
|
||||
6400 0.80 4.1
|
||||
6400 0.99 4.2
|
||||
12800 0.80 4.2
|
||||
25600 0.80 5.2
|
||||
100 0.80 362.6
|
||||
200 0.80 354.9
|
||||
400 0.80 349.7
|
||||
800 0.80 314.4
|
||||
1600 0.80 215.7
|
||||
3200 0.80 94.0
|
||||
6400 0.80 53.5
|
||||
12800 0.80 79.6
|
||||
25600 0.80 77.6
|
||||
======== ========= =========================
|
||||
|
||||
This table suggests that:
|
||||
Second, the effect of varying the mortality of a chain with a single
|
||||
generation.
|
||||
|
||||
======== ========= =========================
|
||||
Capacity Mortality Execution time (user+sys)
|
||||
======== ========= =========================
|
||||
6400 0.20 55.4
|
||||
6400 0.40 54.0
|
||||
6400 0.60 54.0
|
||||
6400 0.80 53.5
|
||||
6400 0.99 54.8
|
||||
======== ========= =========================
|
||||
|
||||
Third, the effect of varying the number of generations (all
|
||||
generations being identical).
|
||||
|
||||
=========== ======== ========= =========================
|
||||
Generations Capacity Mortality Execution time (user+sys)
|
||||
=========== ======== ========= =========================
|
||||
1 6400 0.80 53.5
|
||||
2 6400 0.80 42.4
|
||||
3 6400 0.80 42.1
|
||||
4 6400 0.80 42.2
|
||||
5 6400 0.80 42.2
|
||||
=========== ======== ========= =========================
|
||||
|
||||
These tables suggest that:
|
||||
|
||||
1. The improvement in performance to be gained by getting generation
|
||||
sizes right is dramatic: much bigger than the small improvements to
|
||||
|
|
@ -62,8 +86,43 @@ This table suggests that:
|
|||
|
||||
3. You can make generations too big as well as too small.
|
||||
|
||||
4. There are rapidly diminishing returns to be gained from adding
|
||||
generations.
|
||||
|
||||
.. note::
|
||||
|
||||
:ref:`topic-telemetry` can be used to discover when generations
|
||||
are being collected and what proportion of blocks were found to be
|
||||
alive.
|
||||
|
||||
The table below shows the effect of varying the initial allocation of
|
||||
address space to the arena (using three generations each with capacity
|
||||
6400 kB, mortality 0.80).
|
||||
|
||||
============= ========== =========== =========================
|
||||
Address space Extensions Collections Execution time (user+sys)
|
||||
============= ========== =========== =========================
|
||||
2 32 371 52.0
|
||||
4 21 370 47.0
|
||||
8 0 [1]_ [1]_
|
||||
14 0 [1]_ [1]_
|
||||
16 0 2436 160.5
|
||||
18 0 1135 89.1
|
||||
20 0 673 60.6
|
||||
22 0 484 48.7
|
||||
24 0 400 43.1
|
||||
32 0 368 41.2
|
||||
64 0 368 43.1
|
||||
128 0 368 46.4
|
||||
256 0 368 46.3
|
||||
512 0 368 49.3
|
||||
============= ========== =========== =========================
|
||||
|
||||
.. note::
|
||||
|
||||
.. [1] With this initial allocation of address space, the test
|
||||
case failed to run to completion after thousands of seconds
|
||||
and tens of thousands of garbage collection cycles.
|
||||
|
||||
The lesson here is that the allocation of address space has to be
|
||||
comfortably larger than the working set of the program.
|
||||
|
|
|
|||
|
|
@ -94,8 +94,9 @@ Memory management in various languages
|
|||
|
||||
COBOL was designed by the CODASYL committee in 1959–60 to be a
|
||||
business programming language, and has been extended many
|
||||
times since. It is still the most widely-used programming
|
||||
language (in terms of lines of code in use).
|
||||
times since. A 1997 Gartner Group report estimated that 80% of
|
||||
computer software (by count of source lines) was written in
|
||||
COBOL.
|
||||
|
||||
Prior to 2002, COBOL had no :term:`heap allocation`, and did
|
||||
well in its application domain without it. COBOL 2002 has
|
||||
|
|
@ -456,7 +457,8 @@ Memory management in various languages
|
|||
their keys and values can be dynamically switched from being
|
||||
:term:`strong references` to weak references, and vice versa
|
||||
(by assigning to the ``__mode`` field of the table's
|
||||
metatable).
|
||||
metatable). It also supports :term:`finalization` (by
|
||||
assigning the ``__gc`` field of the object's metatable).
|
||||
|
||||
.. link::
|
||||
|
||||
|
|
|
|||
|
|
@ -572,6 +572,14 @@ allocation and scanning code.
|
|||
If you do not want the arena to remain in the parked state, you
|
||||
must explicitly call :c:func:`mps_arena_release` afterwards.
|
||||
|
||||
.. note::
|
||||
|
||||
It is not normally necessary to call this function: in the
|
||||
:term:`unclamped state`, collections start automatically.
|
||||
However, it may be useful during development and debugging:
|
||||
the more frequently the collector runs, the sooner and more
|
||||
reliably errors are discovered. See :ref:`guide-debug-advice`.
|
||||
|
||||
|
||||
.. c:function:: mps_res_t mps_arena_start_collect(mps_arena_t arena)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
.. _topic-low:
|
||||
|
||||
Handling low memory
|
||||
===================
|
||||
|
||||
What does it mean to be "low on memory" in a virtual memory operating
|
||||
system?
|
||||
|
||||
How does the MPS behave when it's low on memory? Performance degrades
|
||||
(due to running out of zones) and then there are emergency
|
||||
collections.
|
||||
|
||||
How can you handle low memory situations gracefully while still
|
||||
keeping allocation fast and inline?
|
||||
|
|
@ -297,7 +297,7 @@ co-operate with the MPS. The client program must take care
|
|||
that foreign code is not passed the address of a block in
|
||||
a <a class="reference internal" href="m.html#term-moving-memory-manager"><em class="xref std std-term">moving</em></a> <a class="reference internal" href="p.html#term-pool"><em class="xref std std-term">pools</em></a>, or
|
||||
which contain references to blocks in moving pools.</p>
|
||||
<p class="last">The <a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Only)</em></a> <a class="reference internal" href="p.html#term-pool-class"><em class="xref std std-term">pool class</em></a> is designed for this
|
||||
<p class="last">The <a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Object)</em></a> <a class="reference internal" href="p.html#term-pool-class"><em class="xref std std-term">pool class</em></a> is designed for this
|
||||
use case: blocks allocated from this pool do not move and
|
||||
are never protected, and so may be passed safely to
|
||||
foreign code.</p>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ other references to that object, or a garbage collection may be
|
|||
delayed. And even if it does die, the space it occupies may not be
|
||||
re-allocated for some time.</p>
|
||||
<div class="section" id="general-debugging-advice">
|
||||
<h2>4.1. General debugging advice<a class="headerlink" href="#general-debugging-advice" title="Permalink to this headline">¶</a></h2>
|
||||
<span id="guide-debug-advice"></span><h2>4.1. General debugging advice<a class="headerlink" href="#general-debugging-advice" title="Permalink to this headline">¶</a></h2>
|
||||
<ol class="arabic">
|
||||
<li><p class="first">Compile with debugging information turned on (<tt class="docutils literal"><span class="pre">-g</span></tt> on the GCC or
|
||||
Clang command line).</p>
|
||||
|
|
|
|||
|
|
@ -73,11 +73,12 @@ most of the blocks allocated in that generation should be found to be
|
|||
<a class="reference internal" href="../glossary/c.html#term-copying-garbage-collection"><em class="xref std std-term">copying</em></a> them can be avoided
|
||||
entirely). If a generation is collected when its blocks are mostly
|
||||
alive, that is a waste of time.</p>
|
||||
<p>In the table below I give the execution time of <tt class="docutils literal"><span class="pre">test-leaf.scm</span></tt> in
|
||||
<p>In the tables below I give the execution time of <tt class="docutils literal"><span class="pre">test-leaf.scm</span></tt> in
|
||||
the toy Scheme interpreter under different settings for its generation
|
||||
chain. (This test case allocates millions of small short-lived
|
||||
objects.) In each case the AMC pool is given a chain with a single
|
||||
generation with the specified capacity and mortality.</p>
|
||||
chain. (This test case allocates hundreds of millions of small
|
||||
short-lived objects.)</p>
|
||||
<p>First, the effect of varying the capacity of a chain with a single
|
||||
generation.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="19%" />
|
||||
|
|
@ -93,59 +94,124 @@ generation with the specified capacity and mortality.</p>
|
|||
<tbody valign="top">
|
||||
<tr class="row-even"><td>100</td>
|
||||
<td>0.80</td>
|
||||
<td>39.9</td>
|
||||
<td>362.6</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>200</td>
|
||||
<td>0.80</td>
|
||||
<td>30.2</td>
|
||||
<td>354.9</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>400</td>
|
||||
<td>0.80</td>
|
||||
<td>25.5</td>
|
||||
<td>349.7</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>800</td>
|
||||
<td>0.80</td>
|
||||
<td>16.3</td>
|
||||
<td>314.4</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>1600</td>
|
||||
<td>0.80</td>
|
||||
<td>9.0</td>
|
||||
<td>215.7</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>3200</td>
|
||||
<td>0.80</td>
|
||||
<td>5.8</td>
|
||||
<td>94.0</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>6400</td>
|
||||
<td>0.20</td>
|
||||
<td>4.2</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>6400</td>
|
||||
<td>0.40</td>
|
||||
<td>4.1</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>6400</td>
|
||||
<td>0.60</td>
|
||||
<td>4.1</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>4.1</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>6400</td>
|
||||
<td>0.99</td>
|
||||
<td>4.2</td>
|
||||
<td>53.5</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>12800</td>
|
||||
<td>0.80</td>
|
||||
<td>4.2</td>
|
||||
<td>79.6</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>25600</td>
|
||||
<td>0.80</td>
|
||||
<td>5.2</td>
|
||||
<td>77.6</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>This table suggests that:</p>
|
||||
<p>Second, the effect of varying the mortality of a chain with a single
|
||||
generation.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="19%" />
|
||||
<col width="21%" />
|
||||
<col width="60%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr class="row-odd"><th class="head">Capacity</th>
|
||||
<th class="head">Mortality</th>
|
||||
<th class="head">Execution time (user+sys)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr class="row-even"><td>6400</td>
|
||||
<td>0.20</td>
|
||||
<td>55.4</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>6400</td>
|
||||
<td>0.40</td>
|
||||
<td>54.0</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>6400</td>
|
||||
<td>0.60</td>
|
||||
<td>54.0</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>53.5</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>6400</td>
|
||||
<td>0.99</td>
|
||||
<td>54.8</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Third, the effect of varying the number of generations (all
|
||||
generations being identical).</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="21%" />
|
||||
<col width="15%" />
|
||||
<col width="17%" />
|
||||
<col width="47%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr class="row-odd"><th class="head">Generations</th>
|
||||
<th class="head">Capacity</th>
|
||||
<th class="head">Mortality</th>
|
||||
<th class="head">Execution time (user+sys)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr class="row-even"><td>1</td>
|
||||
<td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>53.5</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>2</td>
|
||||
<td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>42.4</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>3</td>
|
||||
<td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>42.1</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>4</td>
|
||||
<td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>42.2</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>5</td>
|
||||
<td>6400</td>
|
||||
<td>0.80</td>
|
||||
<td>42.2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>These tables suggest that:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>The improvement in performance to be gained by getting generation
|
||||
sizes right is dramatic: much bigger than the small improvements to
|
||||
|
|
@ -154,6 +220,8 @@ gained from other techniques.</li>
|
|||
execution time (it does affect the distribution of pause times,
|
||||
however: see <a class="reference internal" href="../topic/collection.html#topic-collection-schedule"><em>Scheduling of collections</em></a>.)</li>
|
||||
<li>You can make generations too big as well as too small.</li>
|
||||
<li>There are rapidly diminishing returns to be gained from adding
|
||||
generations.</li>
|
||||
</ol>
|
||||
<div class="admonition-note admonition">
|
||||
<p class="first admonition-title">Note</p>
|
||||
|
|
@ -161,6 +229,109 @@ however: see <a class="reference internal" href="../topic/collection.html#topic-
|
|||
are being collected and what proportion of blocks were found to be
|
||||
alive.</p>
|
||||
</div>
|
||||
<p>The table below shows the effect of varying the initial allocation of
|
||||
address space to the arena (using three generations each with capacity
|
||||
6400 kB, mortality 0.80).</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="22%" />
|
||||
<col width="17%" />
|
||||
<col width="19%" />
|
||||
<col width="42%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr class="row-odd"><th class="head">Address space</th>
|
||||
<th class="head">Extensions</th>
|
||||
<th class="head">Collections</th>
|
||||
<th class="head">Execution time (user+sys)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr class="row-even"><td>2</td>
|
||||
<td>32</td>
|
||||
<td>371</td>
|
||||
<td>52.0</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>4</td>
|
||||
<td>21</td>
|
||||
<td>370</td>
|
||||
<td>47.0</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>8</td>
|
||||
<td>0</td>
|
||||
<td><a class="footnote-reference" href="#id5" id="id1">[1]</a></td>
|
||||
<td><a class="footnote-reference" href="#id5" id="id2">[1]</a></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>14</td>
|
||||
<td>0</td>
|
||||
<td><a class="footnote-reference" href="#id5" id="id3">[1]</a></td>
|
||||
<td><a class="footnote-reference" href="#id5" id="id4">[1]</a></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>16</td>
|
||||
<td>0</td>
|
||||
<td>2436</td>
|
||||
<td>160.5</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>18</td>
|
||||
<td>0</td>
|
||||
<td>1135</td>
|
||||
<td>89.1</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>20</td>
|
||||
<td>0</td>
|
||||
<td>673</td>
|
||||
<td>60.6</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>22</td>
|
||||
<td>0</td>
|
||||
<td>484</td>
|
||||
<td>48.7</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>24</td>
|
||||
<td>0</td>
|
||||
<td>400</td>
|
||||
<td>43.1</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>32</td>
|
||||
<td>0</td>
|
||||
<td>368</td>
|
||||
<td>41.2</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>64</td>
|
||||
<td>0</td>
|
||||
<td>368</td>
|
||||
<td>43.1</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>128</td>
|
||||
<td>0</td>
|
||||
<td>368</td>
|
||||
<td>46.4</td>
|
||||
</tr>
|
||||
<tr class="row-even"><td>256</td>
|
||||
<td>0</td>
|
||||
<td>368</td>
|
||||
<td>46.3</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>512</td>
|
||||
<td>0</td>
|
||||
<td>368</td>
|
||||
<td>49.3</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="admonition-note admonition">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<table class="last docutils footnote" frame="void" id="id5" rules="none">
|
||||
<colgroup><col class="label" /><col /></colgroup>
|
||||
<tbody valign="top">
|
||||
<tr><td class="label">[1]</td><td><em>(<a class="fn-backref" href="#id1">1</a>, <a class="fn-backref" href="#id2">2</a>, <a class="fn-backref" href="#id3">3</a>, <a class="fn-backref" href="#id4">4</a>)</em> With this initial allocation of address space, the test
|
||||
case failed to run to completion after thousands of seconds
|
||||
and tens of thousands of garbage collection cycles.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>The lesson here is that the allocation of address space has to be
|
||||
comfortably larger than the working set of the program.</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -137,8 +137,9 @@ longer required (see <a class="reference internal" href="../glossary/m.html#term
|
|||
<dt id="term-cobol">COBOL</dt>
|
||||
<dd><p class="first">COBOL was designed by the CODASYL committee in 1959–60 to be a
|
||||
business programming language, and has been extended many
|
||||
times since. It is still the most widely-used programming
|
||||
language (in terms of lines of code in use).</p>
|
||||
times since. A 1997 Gartner Group report estimated that 80% of
|
||||
computer software (by count of source lines) was written in
|
||||
COBOL.</p>
|
||||
<p>Prior to 2002, COBOL had no <a class="reference internal" href="../glossary/h.html#term-heap-allocation"><em class="xref std std-term">heap allocation</em></a>, and did
|
||||
well in its application domain without it. COBOL 2002 has
|
||||
<a class="reference internal" href="../glossary/p.html#term-pointer"><em class="xref std std-term">pointers</em></a> and heap allocation through <tt class="docutils literal"><span class="pre">ALLOCATE</span></tt> and
|
||||
|
|
@ -454,7 +455,8 @@ of weak (hash) tables, which have the unusual feature that
|
|||
their keys and values can be dynamically switched from being
|
||||
<a class="reference internal" href="../glossary/s.html#term-strong-reference"><em class="xref std std-term">strong references</em></a> to weak references, and vice versa
|
||||
(by assigning to the <tt class="docutils literal"><span class="pre">__mode</span></tt> field of the table’s
|
||||
metatable).</p>
|
||||
metatable). It also supports <a class="reference internal" href="../glossary/f.html#term-finalization"><em class="xref std std-term">finalization</em></a> (by
|
||||
assigning the <tt class="docutils literal"><span class="pre">__gc</span></tt> field of the object’s metatable).</p>
|
||||
<div class="admonition-related-link last admonition">
|
||||
<p class="first admonition-title">Related links</p>
|
||||
<p class="last"><a class="reference external" href="http://lua.org">Lua</a>,
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -28,7 +28,7 @@
|
|||
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
||||
<link rel="top" title="Memory Pool System 1.111.0 documentation" href="../index.html" />
|
||||
<link rel="next" title="1. Choosing a pool class" href="intro.html" />
|
||||
<link rel="prev" title="20. Weak references" href="../topic/weak.html" />
|
||||
<link rel="prev" title="19. Weak references" href="../topic/weak.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
<a href="intro.html" title="1. Choosing a pool class"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../topic/weak.html" title="20. Weak references"
|
||||
<a href="../topic/weak.html" title="19. Weak references"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
||||
</ul>
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
</a></p>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="../topic/weak.html"
|
||||
title="previous chapter">20. Weak references</a></p>
|
||||
title="previous chapter">19. Weak references</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="intro.html"
|
||||
title="next chapter">1. Choosing a pool class</a></p><h4>Contact us</h4>
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
<a href="intro.html" title="1. Choosing a pool class"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../topic/weak.html" title="20. Weak references"
|
||||
<a href="../topic/weak.html" title="19. Weak references"
|
||||
>previous</a> |</li>
|
||||
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ pool class to use:</p>
|
|||
<tr class="row-even"><td>yes</td>
|
||||
<td>no</td>
|
||||
<td>none</td>
|
||||
<td><a class="reference internal" href="lo.html#pool-lo"><em>LO (Leaf Only)</em></a></td>
|
||||
<td><a class="reference internal" href="lo.html#pool-lo"><em>LO (Leaf Object)</em></a></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td>yes</td>
|
||||
<td>no</td>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -853,7 +853,7 @@ pointer to array of size classes”?</p>
|
|||
while still keeping the allocation fast and inline? How does the
|
||||
MPS behave when it’s low on memory? Performance degrades (due to
|
||||
running out of zones) and then there are emergency collections.</p>
|
||||
<p><em>Action:</em> created <a class="reference internal" href="topic/low.html#topic-low"><em>Handling low memory</em></a>.</p>
|
||||
<p><em>Action:</em> created <em class="xref std std-ref">topic-low</em>.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<ol class="arabic" start="127">
|
||||
|
|
|
|||
|
|
@ -519,6 +519,14 @@ some objects (such as those near the destination of ambiguous
|
|||
references) even though they are not reachable.</p>
|
||||
<p>If you do not want the arena to remain in the parked state, you
|
||||
must explicitly call <a class="reference internal" href="#mps_arena_release" title="mps_arena_release"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_release()</span></tt></a> afterwards.</p>
|
||||
<div class="admonition-note admonition">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">It is not normally necessary to call this function: in the
|
||||
<a class="reference internal" href="../glossary/u.html#term-unclamped-state"><em class="xref std std-term">unclamped state</em></a>, collections start automatically.
|
||||
However, it may be useful during development and debugging:
|
||||
the more frequently the collector runs, the sooner and more
|
||||
reliably errors are discovered. See <a class="reference internal" href="../guide/debug.html#guide-debug-advice"><em>General debugging advice</em></a>.</p>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ implements copying garbage collection), or was already moved when
|
|||
fixing a previous reference to it, the reference being fixed must be
|
||||
updated (this is the origin of the term “fix”).</p>
|
||||
<p>As a simple example, <tt class="docutils literal"><span class="pre">LOFix</span></tt> is the pool fix method for the
|
||||
<a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Only)</em></a> pool class. It implements a <a class="reference internal" href="../glossary/m.html#term-marking"><em class="xref std std-term">marking</em></a> garbage
|
||||
<a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Object)</em></a> pool class. It implements a <a class="reference internal" href="../glossary/m.html#term-marking"><em class="xref std std-term">marking</em></a> garbage
|
||||
collector, and does not have to worry about scanning preserved objects
|
||||
because it is used to store objects that don’t contain pointers. (It
|
||||
is used in compiler run-time systems to store binary data such as
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ an array and its size as parameters.</p>
|
|||
<p>Each <a class="reference internal" href="../glossary/p.html#term-pool-class"><em class="xref std std-term">pool class</em></a> determines for which objects the stepper
|
||||
function is called. Typically, all validly formatted objects are
|
||||
visited. During a <a class="reference internal" href="../glossary/t.html#term-trace"><em class="xref std std-term">trace</em></a> this will in general be only the
|
||||
<a class="reference internal" href="../glossary/b.html#term-black"><em class="xref std std-term">black</em></a> objects, though the <a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Only)</em></a> pool, for
|
||||
<a class="reference internal" href="../glossary/b.html#term-black"><em class="xref std std-term">black</em></a> objects, though the <a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Object)</em></a> pool, for
|
||||
example, will walk all objects since they are validly formatted
|
||||
whether they are black or <a class="reference internal" href="../glossary/w.html#term-white"><em class="xref std std-term">white</em></a>. <a class="reference internal" href="../glossary/p.html#term-padding-object"><em class="xref std std-term">Padding objects</em></a>
|
||||
may be visited at the pool class’s discretion: the <a class="reference internal" href="../glossary/c.html#term-client-program"><em class="xref std std-term">client
|
||||
|
|
|
|||
|
|
@ -1,110 +0,0 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>19. Handling low memory — Memory Pool System 1.111.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../_static/mps.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../',
|
||||
VERSION: '1.111.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../_static/doctools.js"></script>
|
||||
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
||||
<link rel="top" title="Memory Pool System 1.111.0 documentation" href="../index.html" />
|
||||
<link rel="up" title="Reference" href="index.html" />
|
||||
<link rel="next" title="20. Weak references" href="weak.html" />
|
||||
<link rel="prev" title="18. Telemetry" href="telemetry.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="weak.html" title="20. Weak references"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="telemetry.html" title="18. Telemetry"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
||||
<li><a href="index.html" accesskey="U">Reference</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<div class="section" id="handling-low-memory">
|
||||
<span id="topic-low"></span><h1>19. Handling low memory<a class="headerlink" href="#handling-low-memory" title="Permalink to this headline">¶</a></h1>
|
||||
<p>What does it mean to be “low on memory” in a virtual memory operating
|
||||
system?</p>
|
||||
<p>How does the MPS behave when it’s low on memory? Performance degrades
|
||||
(due to running out of zones) and then there are emergency
|
||||
collections.</p>
|
||||
<p>How can you handle low memory situations gracefully while still
|
||||
keeping allocation fast and inline?</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="telemetry.html"
|
||||
title="previous chapter">18. Telemetry</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="weak.html"
|
||||
title="next chapter">20. Weak references</a></p><h4>Contact us</h4>
|
||||
|
||||
<p class="topless"><a href="mailto:mps-questions@ravenbrook.com">mps-questions@ravenbrook.com</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="weak.html" title="20. Weak references"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="telemetry.html" title="18. Telemetry"
|
||||
>previous</a> |</li>
|
||||
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
||||
<li><a href="index.html" >Reference</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© <a href="../copyright.html">Copyright</a> 2012, Ravenbrook Limited.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue