Next: objects continuations, Previous: objects codes, Up: objects [Index]
Closure objects are actual procedures: closure objects are the ones for
which the procedure?
predicate returns #t
. A closure object
is a fixed length memory block referenced by machine words tagged as
closures; each closure object is associated to either a code object that
implements the procedure or a routine directly coded in assembly. The
memory layout of a closure object is as follows:
|------------------------|-------------| reference to closure heap pointer closure tag 0 1 2 3 4 5 |--------------------|---|---|---|---|---|---| memory block raw memory pointer one slot for every to binary code free variable
the first word in the memory block holds a raw memory pointer referencing the first byte in the code object implementing the closure; the subsequent words (if any) are slots associated to the free variables referenced by the closure’s code.
We can take a look at the free variables referenced by a closure with
the facilities of the library (vicare system $codes)
. In a
normal application: we must not mess with the internals of
closure and code objects.
We start by noticing that in the following example: the function
f
has no “true” free variables, because it accesses only global
variables:
#!r6rs (import (rnrs) (vicare system $codes)) (define a 123) (define (f) a) ($code-freevars ($closure-code f)) ⇒ 0
In the following example: the function f
is the only one
referencing the free variable a
, so such variable is stored
directly in the closure’s slot:
#!r6rs (import (rnrs) (vicare system $codes)) (define f (let ((a 123)) (lambda () a))) ($code-freevars ($closure-code f)) ⇒ 1 ($cpref f 0) ⇒ 123
when there are two such variables:
#!r6rs (import (vicare) (vicare system $codes)) (define f (let ((a 123) (b 456)) (lambda () (list a b)))) ($code-freevars ($closure-code f)) ⇒ 2 ($cpref f 0) ⇒ 456 ($cpref f 1) ⇒ 123
When more than one closure references the same free variable, the storage of the variable is inside a Scheme vector and such vector is referenced by the slots of the closures:
#!r6rs (import (rnrs) (vicare system $codes)) (define f #f) (define g #f) (let ((a 123)) (set! f (lambda () a)) (set! g (lambda (x) (set! a x) a))) ($code-freevars ($closure-code f)) ⇒ 1 ($cpref f 0) ⇒ #(123) ($code-freevars ($closure-code g)) ⇒ 1 ($cpref g 0) ⇒ #(123)
Closure objects are allocated on the heap; to perform the allocation and initialisation for a closure object without free variables we do:
ikptr_t p_closure; ikptr_t s_closure; ikptr_t s_code = ...; p_closure = ik_safe_alloc(pcb, IK_ALIGN(disp_closure_data)); s_closure = p_closure | closure_tag; IK_REF(s_closure, off_closure_code) = s_code + off_code_data;
ik_safe_alloc()
returns an ikptr_t
value representing the aligned
pointer, having the 3 least significant bits set to zero; we add
to it the closure tag (an integer value fitting in 3 bits) which
allows to recognise closures among all the other built in objects.
An integer used to tag ikptr_t
references to closure memory blocks.
An integer representing the bitmask used to extract (with a bitwise
logic AND) the tag from ikptr_t
references to closure objects.
Displacement of code pointer. The number of bytes to add to an untagged pointer to closure to get a pointer to the word in the memory block holding the binary code entry point.
Displacement of free variables. The number of bytes to add to an untagged pointer to closure to get a pointer to the first word in the data area of the memory block.
An integer to add to a tagged ikptr_t
closure reference to get a
pointer to the word in the memory block holding the binary code entry
point.
An integer to add to a tagged ikptr_t
closure reference to get a
pointer to the first word in the data area of the memory block.
Evaluate to true if X is a reference to closure object.
Given a reference to closure object: return the address of the binary code entry point.
Given a reference to closure object: return a reference to the associated code object. Only works for closures associated to code objects.
Given a reference to closure object: return the number of free variables.
Given a reference to closure object: return a reference to value of the free variable at index idx in the data area. idx must be less than the number of free variables in this closure object.
Next: objects continuations, Previous: objects codes, Up: objects [Index]