[gambit-list] is this a bug in ffi?

Marc Feeley feeley at iro.umontreal.ca
Mon Feb 6 15:30:41 EST 2012


On 2012-02-06, at 1:04 PM, REPLeffect wrote:

> 2012/2/6 Marc Feeley <feeley at iro.umontreal.ca>:
>> 
>> On 2012-02-06, at 9:59 AM, Álvaro Castro-Castilla wrote:
>> 
>>> Thank you Marc. Those are all better solutions than my wrapper function.
>>> 
>>> Best regards
>>> 
>>> Álvaro
>> 
>> Actually, using a wrapper function is a good idea to reduce code size.  Its intricacies can be hidden in a macro which generates the appropriate Scheme and C code.  I've written something like this in the past and even posted an example to the Gambit mailing list (unfortunately my mail system's search function is broken right now so I can't find the message).
>> 
>> Marc
>> 
> 
> Marc,
> 
> Is this the message you're referring to?
> 
> https://mercure.iro.umontreal.ca/pipermail/gambit-list/2011-November/005445.html

Yes.  Using that macro as an inspiration, I wrote the following import-enum-constants macro which imports a number of enum constants without using a wrapper function:

(c-declare #<<end-of-c-declare

#include <stdio.h>

typedef enum { A0, B0, C0, D0, E0, F0, G0, H0, I0, J0,
               A1, B1, C1, D1, E1, F1, G1, H1, I1, J1,
               A2, B2, C2, D2, E2, F2, G2, H2, I2, J2,
               A3, B3, C3, D3, E3, F3, G3, H3, I3, J3,
               A4, B4, C4, D4, E4, F4, G4, H4, I4, J4,
               A5, B5, C5, D5, E5, F5, G5, H5, I5, J5,
               A6, B6, C6, D6, E6, F6, G6, H6, I6, J6,
               A7, B7, C7, D7, E7, F7, G7, H7, I7, J7,
               A8, B8, C8, D8, E8, F8, G8, H8, I8, J8,
               A9, B9, C9, D9, E9, F9, G9, H9, I9, J9 } foo;

void f(foo x) { printf("%d\n", x); }

end-of-c-declare
)

;;;---------------------------------------------------------------------------

(define-macro (import-enum-constants type . names)
  (let ((type-str (symbol->string type)))
    `(begin
       ,@(map (lambda (name)
                (let ((name-str (symbol->string name)))
                  `(define ,name
                     ((c-lambda ()
                                ,type
                                ,(string-append
                                  "___ASSIGN_NEW_WITH_INIT(___result_voidstar,"
                                  type-str
                                  ","
                                  name-str
                                  ");"))))))
              names))))

;;;---------------------------------------------------------------------------

(c-define-type foo "foo")

(import-enum-constants foo
  A0 B0 C0 D0 E0 F0 G0 H0 I0 J0
  A1 B1 C1 D1 E1 F1 G1 H1 I1 J1
  A2 B2 C2 D2 E2 F2 G2 H2 I2 J2
  A3 B3 C3 D3 E3 F3 G3 H3 I3 J3
  A4 B4 C4 D4 E4 F4 G4 H4 I4 J4
  A5 B5 C5 D5 E5 F5 G5 H5 I5 J5
  A6 B6 C6 D6 E6 F6 G6 H6 I6 J6
  A7 B7 C7 D7 E7 F7 G7 H7 I7 J7
  A8 B8 C8 D8 E8 F8 G8 H8 I8 J8
  A9 B9 C9 D9 E9 F9 G9 H9 I9 J9
)

(define f (c-lambda (foo) void "f"))

(f A0)
(f F6)
(f J9)


When a wrapper function is used, the macro can be implemented like this:

;;;---------------------------------------------------------------------------

(define-macro (import-enum-constants type . names)

  (define (interval lo hi)
    (if (< lo hi) (cons lo (interval (+ lo 1) hi)) '()))

  (let ((type-str (symbol->string type))
        (nb-names (length names))
        (wrapper (gensym)))
    `(begin
       (define ,wrapper
         (c-lambda (int)
                   ,type
                   ,(string-append
                     "static " type-str " _tmp_[] = {\n"
                     (apply string-append
                            (map (lambda (i name)
                                   (let ((name-str (symbol->string name)))
                                     (string-append
                                      (if (> i 0) "," "")
                                      name-str)))
                                 (interval 0 nb-names)
                                 names))
                     "};\n"
                     "___ASSIGN_NEW_WITH_INIT(___result_voidstar," type-str ",_tmp_[___arg1]);\n")))
       ,@(map (lambda (i name)
                `(define ,name (,wrapper ,i)))
              (interval 0 nb-names)
              names))))

;;;---------------------------------------------------------------------------

The version with the wrapper function is much more compact.  On Mac OS X with LLVM gcc the first version compiles to a 80kb file (roughly 700 bytes of machine code per enum constant that is imported), and the version with a wrapper function compiles to a 20kb file (roughly a factor of 5 times more compact).

Marc




More information about the Gambit-list mailing list