[gambit-list] equiv of __FILE__ and __LINE__
Marc Feeley
feeley at iro.umontreal.ca
Thu May 7 15:23:03 EDT 2009
On 7-May-09, at 2:40 PM, lowly coder wrote:
> Your response to 2 was really enlightening.
>
> More on 3:
>
> ~:$ cat test.scm
> (define source? 10)
> (define ##source? 10)
> (pp source?)
> (pp ##source?)
> ~:$ gsi test.scm
> 10
> 10
>
>
> This surprised me a bit ... initially, intuitively, I had a notion
> that ##blah was a blah that had it's value hard coded internally in
> gambit (so that even if the user did weird things to his/her
> environment, I can still get the 'system functions').
>
> In gambit, are ##-vars treated just like regular ##-vars ?
Yes, ##car and car are two global variables.
But that is not the whole story because the compiler can be told,
using a declaration, that it can assume that global variables are
bound to their predefined value. So in the code
(let ()
(declare (standard-bindings))
(car (f x)))
the programmer is telling the compiler that it can assume that car is
bound to the predefined car procedure. This allows the compiler to
inline the car procedure. The code (once transformed by the compiler)
becomes:
(let ((temp.0 (f x)))
(if ('#<procedure #2 ##pair?> temp.0)
('#<procedure #3 ##car> temp.0)
(car temp.0)))
So the logic of the car procedure, including the type test, is inlined
at the location of the original call to car. Note that if the type
test fails, the car procedure in the runtime library is called, and it
will raise the appropriate exception (moreover the continuation of
that exception will be the same continuation that was passed to the
original call to car).
If the programmer wants the compiler to assume that the type check
will succeed (i.e. the result of (f x) is always a pair) then the (not
safe) declaration can be added:
(let ()
(declare (standard-bindings) (not safe))
(car (f x)))
After the compiler's transformations the code becomes:
('#<procedure #2 ##car> (f x))
Here only a call to the ##car primitive remains. This primitive will
be inlined by the back-end of the compiler, which will generate a call
to the ___CAR(obj) C macro defined in include/gambit.h . The ___CAR
macro is defined like this:
#define ___CAR(obj)___PAIR_CAR(obj)
#define ___PAIR_CAR(obj)(*(___BODY_AS(obj,___tPAIR)+___PAIR_CAR_OFS))
#define ___BODY_AS(obj,tag)(___UNTAG_AS(obj,tag)+___BODY_OFS)
#define ___UNTAG_AS(obj,tag)___CAST(___WORD*,(obj)-(tag))
#define ___CAST(type,val)((type)(val))
#define ___tPAIR 3
#define ___PAIR_CAR_OFS 1
#define ___BODY_OFS 1
#define ___WORD int /* usually */
so in the end, the call to car has become the C code:
*((int*)(obj-3)+2)
which on many processor architectures, is a single machine instruction
(because the C compiler combines the substraction and addition of the
constants into a single offset).
Marc
More information about the Gambit-list
mailing list