[gambit-list] Creating and returning scheme lists inside C
Marc Feeley
feeley at iro.umontreal.ca
Fri Dec 30 22:36:55 EST 2005
On 30-Dec-05, at 9:44 PM, Christian wrote:
> Marc: can you give more info? Which parts of the Gambit source do
> you recommend to try to understand first?
>
>> ___S8 one, two, three;
>> one = 1;
>> two = 2;
>> three = 3;
>>
>> return
>> ___CONS(one,
>> ___CONS(two,
>> ___CONS(three,
>> ___NUL)));
>
> Note that you would also have to convert the ___S8 values to
> ___SCMOBJ, using ___FIX() probably.
Some quick notes about allocating Scheme objects in C code...
Scheme objects can be allocated using one of 3 allocation policies:
___MOVABLE the object's location can change as a result of
garbage collection
___STILL the object's location cannot change as a result of
garbage collection
___PERM the object's location cannot change and it is never
reclaimed by the GC
The macro ___CONS(car,cdr) allocates movable pairs,
___BEGIN_ALLOC_VECTOR(n) allocates movable vectors, etc. Movable
objects are allocated by incrementing the heap pointer (the local
variable ___hp which is a copy of the hp field of the processor state
structure). Still pairs are allocated with ___make_pair
(car,cdr,policy), still vectors are allocated with ___make_vector
(length,init,policy), etc. Still objects have a reference count,
initialized to 1 at allocation time, which is taken into account by
the garbage collector to infer liveness (in **addition** to the
normal roots). This makes it easy to manipulate still objects from C
code because the garbage collector does not have to be aware of local
C variables referencing still objects (as long as the reference count
is > 0 the references will stay valid).
Although it is technically possible, it is a bad idea to allocate
movable objects from C code because any allocation can cause a
garbage collection (and the C stack is neither treated as a root or
updated by the garbage collector).
So the simplest is for C code to only allocate still Scheme objects,
and to decrement the reference count back to 0 when the C code
returns the object to Scheme code.
Below is an example inspired from sample code in the Gambit manual.
Marc
(c-declare #<<end-c-declare
___SCMOBJ square_alist (int n)
{
/* builds an association list of the squares of 0 to n-1 */
___SCMOBJ result = ___NUL; /* start with the empty list */
int i = n;
/* build the list starting at the tail */
while (--i >= 0)
{
___SCMOBJ elem;
___SCMOBJ new_result;
/*
* Invariant: result is either the empty list or a ___STILL pair
* with reference count equal to 1. This is important because
* it is possible that ___make_pair will invoke the garbage
* collector and we don't want the reference in result to become
* invalid (which would be the case if result was a ___MOVABLE
* pair or if it had a zero reference count).
*/
elem = ___EXT(___make_pair) (___FIX(i), ___FIX(i*i), ___STILL);
if (___FIXNUMP(elem))
{
___EXT(___release_scmobj) (result); /* allow GC to reclaim
result */
return elem; /* fixnum indicates allocation failed */
}
/*
* Note that elem will be a ___STILL object with reference count
* equal to 1, so there is no risk that it will be reclaimed or
* moved if the following call to ___make_pair invokes the
* garbage collector.
*/
new_result = ___EXT(___make_pair) (elem, result, ___STILL);
/*
* We can zero the reference count of elem and result (if not
* the empty list) because the pair now references these objects
* and the pair's reference count is > 0 (it can't be reclaimed
* or moved by the garbage collector).
*/
___EXT(___release_scmobj) (elem);
___EXT(___release_scmobj) (result);
result = new_result;
if (___FIXNUMP(result))
return result; /* fixnum indicates allocation failed */
}
/*
* Note that result is either the empty list or a ___STILL pair with
* a reference count equal to 1. The reference count must be
* decremented to 0 when it is handed back to the Scheme world, so
* that it can be reclaimed when the Scheme world no longer
* references it.
*/
___EXT(___release_scmobj) (result);
return result;
}
end-c-declare
)
(define square-alist (c-lambda (int) scheme-object "square_alist"))
(pp (square-alist 10)) ; test it
More information about the Gambit-list
mailing list