0.6.7.22: removed CVS dollar-Header-dollar tags from sources
[sbcl.git] / src / code / target-alieneval.lisp
1 ;;;; This file contains parts of the ALIEN implementation that
2 ;;;; are not part of the compiler.
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
12
13 (in-package "SB!ALIEN")
14 \f
15 ;;;; alien variables
16
17 ;;; Make a string out of the symbol, converting all uppercase letters to
18 ;;; lower case and hyphens into underscores.
19 (eval-when (:compile-toplevel :load-toplevel :execute)
20   (defun guess-alien-name-from-lisp-name (lisp-name)
21     (declare (type symbol lisp-name))
22     (nsubstitute #\_ #\- (string-downcase (symbol-name lisp-name)))))
23
24 ;;; The opposite of GUESS-ALIEN-NAME-FROM-LISP-NAME. Make a symbol out
25 ;;; of the string, converting all lowercase letters to uppercase and
26 ;;; underscores into hyphens.
27 (eval-when (:compile-toplevel :load-toplevel :execute)
28   (defun guess-lisp-name-from-alien-name (alien-name)
29     (declare (type simple-string alien-name))
30     (intern (nsubstitute #\- #\_ (string-upcase alien-name)))))
31
32 ;;; Extract the Lisp and alien names from NAME. If only one is given,
33 ;;; guess the other.
34 (eval-when (:compile-toplevel :load-toplevel :execute)
35   (defun pick-lisp-and-alien-names (name)
36     (etypecase name
37       (string
38        (values (guess-lisp-name-from-alien-name name) name))
39       (symbol
40        (values name (guess-alien-name-from-lisp-name name)))
41       (list
42        (unless (proper-list-of-length-p name 2)
43          (error "badly formed alien name"))
44        (values (cadr name) (car name))))))
45
46 (defmacro def-alien-variable (name type &environment env)
47   #!+sb-doc
48   "Define NAME as an external alien variable of type TYPE. NAME should be
49    a list of a string holding the alien name and a symbol to use as the Lisp
50    name. If NAME is just a symbol or string, then the other name is guessed
51    from the one supplied."
52   (multiple-value-bind (lisp-name alien-name) (pick-lisp-and-alien-names name)
53     (with-auxiliary-alien-types env
54       (let ((alien-type (parse-alien-type type env)))
55         `(eval-when (:compile-toplevel :load-toplevel :execute)
56            ,@(when *new-auxiliary-types*
57                `((%def-auxiliary-alien-types ',*new-auxiliary-types*)))
58            (%def-alien-variable ',lisp-name
59                                 ',alien-name
60                                 ',alien-type))))))
61
62 ;;; Do the actual work of DEF-ALIEN-VARIABLE.
63 (eval-when (:compile-toplevel :load-toplevel :execute)
64   (defun %def-alien-variable (lisp-name alien-name type)
65     (setf (info :variable :kind lisp-name) :alien)
66     (setf (info :variable :where-from lisp-name) :defined)
67     (clear-info :variable :constant-value lisp-name)
68     (setf (info :variable :alien-info lisp-name)
69           (make-heap-alien-info :type type
70                                 :sap-form `(foreign-symbol-address
71                                             ',alien-name)))))
72
73 (defmacro extern-alien (name type &environment env)
74   #!+sb-doc
75   "Access the alien variable named NAME, assuming it is of type TYPE. This
76    is SETFable."
77   (let ((alien-name (etypecase name
78                       (symbol (guess-alien-name-from-lisp-name name))
79                       (string name))))
80     `(%heap-alien ',(make-heap-alien-info
81                      :type (parse-alien-type type env)
82                      :sap-form `(foreign-symbol-address ',alien-name)))))
83
84 (defmacro with-alien (bindings &body body &environment env)
85   #!+sb-doc
86   "Establish some local alien variables. Each BINDING is of the form:
87      VAR TYPE [ ALLOCATION ] [ INITIAL-VALUE | EXTERNAL-NAME ]
88    ALLOCATION should be one of:
89      :LOCAL (the default)
90        The alien is allocated on the stack, and has dynamic extent.
91      :STATIC
92        The alien is allocated on the heap, and has infinite extent. The alien
93        is allocated at load time, so the same piece of memory is used each time
94        this form executes.
95      :EXTERN
96        No alien is allocated, but VAR is established as a local name for
97        the external alien given by EXTERNAL-NAME."
98   (with-auxiliary-alien-types env
99     (dolist (binding (reverse bindings))
100       (destructuring-bind
101           (symbol type &optional (opt1 nil opt1p) (opt2 nil opt2p))
102           binding
103         (let ((alien-type (parse-alien-type type env)))
104           (multiple-value-bind (allocation initial-value)
105               (if opt2p
106                   (values opt1 opt2)
107                   (case opt1
108                     (:extern
109                      (values opt1 (guess-alien-name-from-lisp-name symbol)))
110                     (:static
111                      (values opt1 nil))
112                     (t
113                      (values :local opt1))))
114             (setf body
115                   (ecase allocation
116                     #+nil
117                     (:static
118                      (let ((sap
119                             (make-symbol (concatenate 'string "SAP-FOR-"
120                                                       (symbol-name symbol)))))
121                        `((let ((,sap (load-time-value (%make-alien ...))))
122                            (declare (type system-area-pointer ,sap))
123                            (symbol-macrolet
124                             ((,symbol (sap-alien ,sap ,type)))
125                             ,@(when initial-value
126                                 `((setq ,symbol ,initial-value)))
127                             ,@body)))))
128                     (:extern
129                      (let ((info (make-heap-alien-info
130                                   :type alien-type
131                                   :sap-form `(foreign-symbol-address
132                                               ',initial-value))))
133                        `((symbol-macrolet
134                           ((,symbol (%heap-alien ',info)))
135                           ,@body))))
136                     (:local
137                      (let ((var (gensym))
138                            (initval (if initial-value (gensym)))
139                            (info (make-local-alien-info :type alien-type)))
140                        `((let ((,var (make-local-alien ',info))
141                                ,@(when initial-value
142                                    `((,initval ,initial-value))))
143                            (note-local-alien-type ',info ,var)
144                            (multiple-value-prog1
145                                (symbol-macrolet
146                                 ((,symbol (local-alien ',info ,var)))
147                                 ,@(when initial-value
148                                     `((setq ,symbol ,initval)))
149                                 ,@body)
150                                (dispose-local-alien ',info ,var))))))))))))
151     (verify-local-auxiliaries-okay)
152     `(symbol-macrolet ((&auxiliary-type-definitions&
153                         ,(append *new-auxiliary-types*
154                                  (auxiliary-type-definitions env))))
155        ,@body)))
156 \f
157 ;;;; runtime C values that don't correspond directly to Lisp types
158
159 ;;; ALIEN-VALUE
160 ;;;
161 ;;; Note: The DEFSTRUCT for ALIEN-VALUE lives in a separate file
162 ;;; 'cause it has to be real early in the cold-load order.
163 #!-sb-fluid (declaim (freeze-type alien-value))
164 (def!method print-object ((value alien-value) stream)
165   (print-unreadable-object (value stream)
166     (format stream
167             "~S :SAP #X~8,'0X"
168             'alien-value
169             (sap-int (alien-value-sap value)))))
170
171 #!-sb-fluid (declaim (inline null-alien))
172 (defun null-alien (x)
173   #!+sb-doc
174   "Return true if X (which must be an ALIEN pointer) is null, false otherwise."
175   (zerop (sap-int (alien-sap x))))
176
177 (defmacro sap-alien (sap type &environment env)
178   #!+sb-doc
179   "Convert the system area pointer SAP to an ALIEN of the specified TYPE (not
180    evaluated.) TYPE must be pointer-like."
181   (let ((alien-type (parse-alien-type type env)))
182     (if (eq (compute-alien-rep-type alien-type) 'system-area-pointer)
183         `(%sap-alien ,sap ',alien-type)
184         (error "cannot make aliens of type ~S out of SAPs" type))))
185
186 (defun %sap-alien (sap type)
187   (declare (type system-area-pointer sap)
188            (type alien-type type))
189   (make-alien-value :sap sap :type type))
190
191 (defun alien-sap (alien)
192   #!+sb-doc
193   "Return a System-Area-Pointer pointing to Alien's data."
194   (declare (type alien-value alien))
195   (alien-value-sap alien))
196 \f
197 ;;;; allocation/deallocation of heap aliens
198
199 (defmacro make-alien (type &optional size &environment env)
200   #!+sb-doc
201   "Allocate an alien of type TYPE and return an alien pointer to it. If SIZE
202    is supplied, how it is interpreted depends on TYPE. If TYPE is an array
203    type, SIZE is used as the first dimension for the allocated array. If TYPE
204    is not an array, then SIZE is the number of elements to allocate. The
205    memory is allocated using ``malloc'', so it can be passed to foreign
206    functions which use ``free''."
207   (let ((alien-type (if (alien-type-p type)
208                         type
209                         (parse-alien-type type env))))
210     (multiple-value-bind (size-expr element-type)
211         (if (alien-array-type-p alien-type)
212             (let ((dims (alien-array-type-dimensions alien-type)))
213               (cond
214                (size
215                 (unless dims
216                   (error
217                    "cannot override the size of zero-dimensional arrays"))
218                 (when (constantp size)
219                   (setf alien-type (copy-alien-array-type alien-type))
220                   (setf (alien-array-type-dimensions alien-type)
221                         (cons (eval size) (cdr dims)))))
222                (dims
223                 (setf size (car dims)))
224                (t
225                 (setf size 1)))
226               (values `(* ,size ,@(cdr dims))
227                       (alien-array-type-element-type alien-type)))
228             (values (or size 1) alien-type))
229       (let ((bits (alien-type-bits element-type))
230             (alignment (alien-type-alignment element-type)))
231         (unless bits
232           (error "The size of ~S is unknown."
233                  (unparse-alien-type element-type)))
234         (unless alignment
235           (error "The alignment of ~S is unknown."
236                  (unparse-alien-type element-type)))
237         `(%sap-alien (%make-alien (* ,(align-offset bits alignment)
238                                      ,size-expr))
239                      ',(make-alien-pointer-type :to alien-type))))))
240
241 ;;; Allocate a block of memory at least BITS bits long and return a
242 ;;; system area pointer to it.
243 #!-sb-fluid (declaim (inline %make-alien))
244 (defun %make-alien (bits)
245   (declare (type index bits) (optimize-interface (safety 2)))
246   (alien-funcall (extern-alien "malloc" (function system-area-pointer unsigned))
247                  (ash (the index (+ bits 7)) -3)))
248
249 #!-sb-fluid (declaim (inline free-alien))
250 (defun free-alien (alien)
251   #!+sb-doc
252   "Dispose of the storage pointed to by ALIEN. ALIEN must have been allocated
253    by MAKE-ALIEN or ``malloc''."
254   (alien-funcall (extern-alien "free" (function (values) system-area-pointer))
255                  (alien-sap alien))
256   nil)
257 \f
258 ;;;; the SLOT operator
259
260 ;;; Find the field named SLOT, or die trying.
261 (defun slot-or-lose (type slot)
262   (declare (type alien-record-type type)
263            (type symbol slot))
264   (or (find slot (alien-record-type-fields type)
265             :key #'alien-record-field-name)
266       (error "There is no slot named ~S in ~S" slot type)))
267
268 ;;; Extract the value from the named slot from the record ALIEN. If
269 ;;; ALIEN is actually a pointer, then DEREF it first.
270 (defun slot (alien slot)
271   #!+sb-doc
272   "Extract SLOT from the Alien STRUCT or UNION ALIEN. May be set with SETF."
273   (declare (type alien-value alien)
274            (type symbol slot)
275            (optimize (inhibit-warnings 3)))
276   (let ((type (alien-value-type alien)))
277     (etypecase type
278       (alien-pointer-type
279        (slot (deref alien) slot))
280       (alien-record-type
281        (let ((field (slot-or-lose type slot)))
282          (extract-alien-value (alien-value-sap alien)
283                               (alien-record-field-offset field)
284                               (alien-record-field-type field)))))))
285
286 ;;; Deposit the value in the specified slot of the record ALIEN. If
287 ;;; the ALIEN is really a pointer, DEREF it first. The compiler uses
288 ;;; this when it can't figure out anything better.
289 (defun %set-slot (alien slot value)
290   (declare (type alien-value alien)
291            (type symbol slot)
292            (optimize (inhibit-warnings 3)))
293   (let ((type (alien-value-type alien)))
294     (etypecase type
295       (alien-pointer-type
296        (%set-slot (deref alien) slot value))
297       (alien-record-type
298        (let ((field (slot-or-lose type slot)))
299          (deposit-alien-value (alien-value-sap alien)
300                               (alien-record-field-offset field)
301                               (alien-record-field-type field)
302                               value))))))
303
304 ;;; Compute the address of the specified slot and return a pointer to it.
305 (defun %slot-addr (alien slot)
306   (declare (type alien-value alien)
307            (type symbol slot)
308            (optimize (inhibit-warnings 3)))
309   (let ((type (alien-value-type alien)))
310     (etypecase type
311       (alien-pointer-type
312        (%slot-addr (deref alien) slot))
313       (alien-record-type
314        (let* ((field (slot-or-lose type slot))
315               (offset (alien-record-field-offset field))
316               (field-type (alien-record-field-type field)))
317          (%sap-alien (sap+ (alien-sap alien) (/ offset sb!vm:byte-bits))
318                      (make-alien-pointer-type :to field-type)))))))
319 \f
320 ;;;; the DEREF operator
321
322 ;;; Does most of the work of the different DEREF methods. Returns two values:
323 ;;; the type and the offset (in bits) of the refered to alien.
324 (defun deref-guts (alien indices)
325   (declare (type alien-value alien)
326            (type list indices)
327            (values alien-type integer))
328   (let ((type (alien-value-type alien)))
329     (etypecase type
330       (alien-pointer-type
331        (when (cdr indices)
332          (error "too many indices when derefing ~S: ~D"
333                 type
334                 (length indices)))
335        (let ((element-type (alien-pointer-type-to type)))
336          (values element-type
337                  (if indices
338                      (* (align-offset (alien-type-bits element-type)
339                                       (alien-type-alignment element-type))
340                         (car indices))
341                      0))))
342       (alien-array-type
343        (unless (= (length indices) (length (alien-array-type-dimensions type)))
344          (error "incorrect number of indices when derefing ~S: ~D"
345                 type (length indices)))
346        (labels ((frob (dims indices offset)
347                   (if (null dims)
348                       offset
349                       (frob (cdr dims) (cdr indices)
350                         (+ (if (zerop offset)
351                                0
352                                (* offset (car dims)))
353                            (car indices))))))
354          (let ((element-type (alien-array-type-element-type type)))
355            (values element-type
356                    (* (align-offset (alien-type-bits element-type)
357                                     (alien-type-alignment element-type))
358                       (frob (alien-array-type-dimensions type)
359                         indices 0)))))))))
360
361 ;;; Dereference the alien and return the results.
362 (defun deref (alien &rest indices)
363   #!+sb-doc
364   "De-reference an Alien pointer or array. If an array, the indices are used
365    as the indices of the array element to access. If a pointer, one index can
366    optionally be specified, giving the equivalent of C pointer arithmetic."
367   (declare (type alien-value alien)
368            (type list indices)
369            (optimize (inhibit-warnings 3)))
370   (multiple-value-bind (target-type offset) (deref-guts alien indices)
371     (extract-alien-value (alien-value-sap alien)
372                          offset
373                          target-type)))
374
375 (defun %set-deref (alien value &rest indices)
376   (declare (type alien-value alien)
377            (type list indices)
378            (optimize (inhibit-warnings 3)))
379   (multiple-value-bind (target-type offset) (deref-guts alien indices)
380     (deposit-alien-value (alien-value-sap alien)
381                          offset
382                          target-type
383                          value)))
384
385 (defun %deref-addr (alien &rest indices)
386   (declare (type alien-value alien)
387            (type list indices)
388            (optimize (inhibit-warnings 3)))
389   (multiple-value-bind (target-type offset) (deref-guts alien indices)
390     (%sap-alien (sap+ (alien-value-sap alien) (/ offset sb!vm:byte-bits))
391                 (make-alien-pointer-type :to target-type))))
392 \f
393 ;;;; accessing heap alien variables
394
395 (defun %heap-alien (info)
396   (declare (type heap-alien-info info)
397            (optimize (inhibit-warnings 3)))
398   (extract-alien-value (eval (heap-alien-info-sap-form info))
399                        0
400                        (heap-alien-info-type info)))
401
402 (defun %set-heap-alien (info value)
403   (declare (type heap-alien-info info)
404            (optimize (inhibit-warnings 3)))
405   (deposit-alien-value (eval (heap-alien-info-sap-form info))
406                        0
407                        (heap-alien-info-type info)
408                        value))
409
410 (defun %heap-alien-addr (info)
411   (declare (type heap-alien-info info)
412            (optimize (inhibit-warnings 3)))
413   (%sap-alien (eval (heap-alien-info-sap-form info))
414               (make-alien-pointer-type :to (heap-alien-info-type info))))
415 \f
416 ;;;; accessing local aliens
417
418 (defun make-local-alien (info)
419   (let* ((alien (eval `(make-alien ,(local-alien-info-type info))))
420          (alien-sap (alien-sap alien)))
421     (finalize
422      alien
423      #'(lambda ()
424          (alien-funcall
425           (extern-alien "free" (function (values) system-area-pointer))
426           alien-sap)))
427     alien))
428
429 (defun note-local-alien-type (info alien)
430   (declare (ignore info alien))
431   nil)
432
433 (defun local-alien (info alien)
434   (declare (ignore info))
435   (deref alien))
436
437 (defun %set-local-alien (info alien value)
438   (declare (ignore info))
439   (setf (deref alien) value))
440
441 (define-setf-expander local-alien (&whole whole info alien)
442   (let ((value (gensym))
443         (info (if (and (consp info)
444                        (eq (car info) 'quote))
445                   (second info)
446                   (error "Something is wrong; local-alien-info not found: ~S"
447                          whole))))
448     (values nil
449             nil
450             (list value)
451             (if sb!c:*converting-for-interpreter*
452                 `(%set-local-alien ',info ,alien ,value)
453                 `(if (%local-alien-forced-to-memory-p ',info)
454                      (%set-local-alien ',info ,alien ,value)
455                      (setf ,alien
456                            (deport ,value ',(local-alien-info-type info)))))
457             whole)))
458
459 (defun %local-alien-forced-to-memory-p (info)
460   (local-alien-info-force-to-memory-p info))
461
462 (defun %local-alien-addr (info alien)
463   (declare (type local-alien-info info))
464   (unless (local-alien-info-force-to-memory-p info)
465     (error "~S isn't forced to memory. Something went wrong." alien))
466   alien)
467
468 (defun dispose-local-alien (info alien)
469   (declare (ignore info))
470   (cancel-finalization alien)
471   (free-alien alien))
472 \f
473 ;;;; the CAST macro
474
475 (defmacro cast (alien type &environment env)
476   #!+sb-doc
477   "Convert ALIEN to an Alien of the specified TYPE (not evaluated.)  Both types
478    must be Alien array, pointer or function types."
479   `(%cast ,alien ',(parse-alien-type type env)))
480
481 (defun %cast (alien target-type)
482   (declare (type alien-value alien)
483            (type alien-type target-type)
484            (optimize-interface (safety 2))
485            (optimize (inhibit-warnings 3)))
486   (if (or (alien-pointer-type-p target-type)
487           (alien-array-type-p target-type)
488           (alien-function-type-p target-type))
489       (let ((alien-type (alien-value-type alien)))
490         (if (or (alien-pointer-type-p alien-type)
491                 (alien-array-type-p alien-type)
492                 (alien-function-type-p alien-type))
493             (naturalize (alien-value-sap alien) target-type)
494             (error "~S cannot be casted." alien)))
495       (error "cannot cast to alien type ~S" (unparse-alien-type target-type))))
496 \f
497 ;;;; the ALIEN-SIZE macro
498
499 (defmacro alien-size (type &optional (units :bits) &environment env)
500   #!+sb-doc
501   "Return the size of the alien type TYPE. UNITS specifies the units to
502    use and can be either :BITS, :BYTES, or :WORDS."
503   (let* ((alien-type (parse-alien-type type env))
504          (bits (alien-type-bits alien-type)))
505     (if bits
506         (values (ceiling bits
507                          (ecase units
508                            (:bits 1)
509                            (:bytes sb!vm:byte-bits)
510                            (:words sb!vm:word-bits))))
511         (error "unknown size for alien type ~S"
512                (unparse-alien-type alien-type)))))
513 \f
514 ;;;; NATURALIZE, DEPORT, EXTRACT-ALIEN-VALUE, DEPOSIT-ALIEN-VALUE
515
516 (defun naturalize (alien type)
517   (declare (type alien-type type))
518   (funcall (coerce (compute-naturalize-lambda type) 'function)
519            alien type))
520
521 (defun deport (value type)
522   (declare (type alien-type type))
523   (funcall (coerce (compute-deport-lambda type) 'function)
524            value type))
525
526 (defun extract-alien-value (sap offset type)
527   (declare (type system-area-pointer sap)
528            (type unsigned-byte offset)
529            (type alien-type type))
530   (funcall (coerce (compute-extract-lambda type) 'function)
531            sap offset type))
532
533 (defun deposit-alien-value (sap offset type value)
534   (declare (type system-area-pointer sap)
535            (type unsigned-byte offset)
536            (type alien-type type))
537   (funcall (coerce (compute-deposit-lambda type) 'function)
538            sap offset type value))
539 \f
540 ;;;; ALIEN-FUNCALL, DEF-ALIEN-ROUTINE
541
542 (defun alien-funcall (alien &rest args)
543   #!+sb-doc
544   "Call the foreign function ALIEN with the specified arguments. ALIEN's
545    type specifies the argument and result types."
546   (declare (type alien-value alien))
547   (let ((type (alien-value-type alien)))
548     (typecase type
549       (alien-pointer-type
550        (apply #'alien-funcall (deref alien) args))
551       (alien-function-type
552        (unless (= (length (alien-function-type-arg-types type))
553                   (length args))
554          (error "wrong number of arguments for ~S~%expected ~D, got ~D"
555                 type
556                 (length (alien-function-type-arg-types type))
557                 (length args)))
558        (let ((stub (alien-function-type-stub type)))
559          (unless stub
560            (setf stub
561                  (let ((fun (gensym))
562                        (parms (make-gensym-list (length args))))
563                    (compile nil
564                             `(lambda (,fun ,@parms)
565                                (declare (type (alien ,type) ,fun))
566                                (alien-funcall ,fun ,@parms)))))
567            (setf (alien-function-type-stub type) stub))
568          (apply stub alien args)))
569       (t
570        (error "~S is not an alien function." alien)))))
571
572 (defmacro def-alien-routine (name result-type &rest args &environment env)
573   #!+sb-doc
574   "Def-C-Routine Name Result-Type
575                     {(Arg-Name Arg-Type [Style])}*
576
577   Define a foreign interface function for the routine with the specified Name,
578   which may be either a string, symbol or list of the form (string symbol).
579   Return-Type is the Alien type for the function return value. VOID may be
580   used to specify a function with no result.
581
582   The remaining forms specifiy individual arguments that are passed to the
583   routine. Arg-Name is a symbol that names the argument, primarily for
584   documentation. Arg-Type is the C-Type of the argument. Style specifies the
585   say that the argument is passed.
586
587   :IN
588         An :In argument is simply passed by value. The value to be passed is
589         obtained from argument(s) to the interface function. No values are
590         returned for :In arguments. This is the default mode.
591
592   :OUT
593         The specified argument type must be a pointer to a fixed sized object.
594         A pointer to a preallocated object is passed to the routine, and the
595         the object is accessed on return, with the value being returned from
596         the interface function. :OUT and :IN-OUT cannot be used with pointers
597         to arrays, records or functions.
598
599   :COPY
600         Similar to :IN, except that the argument values are stored in on
601         the stack, and a pointer to the object is passed instead of
602         the values themselves.
603
604   :IN-OUT
605         A combination of :OUT and :COPY. A pointer to the argument is passed,
606         with the object being initialized from the supplied argument and
607         the return value being determined by accessing the object on return."
608   (multiple-value-bind (lisp-name alien-name)
609       (pick-lisp-and-alien-names name)
610     (collect ((docs) (lisp-args) (arg-types) (alien-vars)
611               (alien-args) (results))
612       (dolist (arg args)
613         (if (stringp arg)
614             (docs arg)
615             (destructuring-bind (name type &optional (style :in)) arg
616               (unless (member style '(:in :copy :out :in-out))
617                 (error "bogus argument style ~S in ~S" style arg))
618               (unless (eq style :out)
619                 (lisp-args name))
620               (when (and (member style '(:out :in-out))
621                          (typep (parse-alien-type type env)
622                                 'alien-pointer-type))
623                 (error "can't use :OUT or :IN-OUT on pointer-like type:~%  ~S"
624                        type))
625               (cond ((eq style :in)
626                      (arg-types type)
627                      (alien-args name))
628                     (t
629                      (arg-types `(* ,type))
630                      (if (eq style :out)
631                          (alien-vars `(,name ,type))
632                          (alien-vars `(,name ,type ,name)))
633                      (alien-args `(addr ,name))))
634               (when (or (eq style :out) (eq style :in-out))
635                 (results name)))))
636       `(defun ,lisp-name ,(lisp-args)
637          ,@(docs)
638          (with-alien
639              ((,lisp-name (function ,result-type ,@(arg-types))
640                           :extern ,alien-name)
641               ,@(alien-vars))
642              ,(if (alien-values-type-p result-type)
643                   (let ((temps (make-gensym-list
644                                 (length
645                                  (alien-values-type-values result-type)))))
646                     `(multiple-value-bind ,temps
647                          (alien-funcall ,lisp-name ,@(alien-args))
648                        (values ,@temps ,@(results))))
649                   `(values (alien-funcall ,lisp-name ,@(alien-args))
650                            ,@(results))))))))
651 \f
652 (defun alien-typep (object type)
653   #!+sb-doc
654   "Return T iff OBJECT is an alien of type TYPE."
655   (let ((lisp-rep-type (compute-lisp-rep-type type)))
656     (if lisp-rep-type
657         (typep object lisp-rep-type)
658         (and (alien-value-p object)
659              (alien-subtype-p (alien-value-type object) type)))))