Hello,
Lucas Bergman <lucas@...> writes:
> I'm writing some code that uses the SBCL FFI, and I'm having the
> "could not optimize away %SAP-ALIEN" problem, which seems to be fairly
> common, judging from what Google said. Judging from what came up in
> Google searches for the above, this message means that calling the
> offending closure will certainly generate great ugly gobs of
> short-lived garbage and generally ruin your day.
This is a particular case of the general problem of boxing. Lisp
objects carry type information with them, so machine types are put in
boxes; ALIENs are a kind of such boxes. If you pass a value to a
remote (independently compiled) function, put it into a generic store
(list, untyped array, global variable), boxing is unavoidable. The
only exception is when all the dataflow from lisp object producer
(such as MAKE-ALIEN, result of foreign function call) to the lisp
object consumer (e.g. alien functions, or storing in a typed array or
alien structure slot) is traceable by the compiler.
> It's not clear to me how one avoids this. Most people, when
> confronted with this problem, claimed they can solve it by putting
> some type declarations,
Or, yeah. "Just declare everything to be of type FIXNUM". Type
declarations solve two problems:
1. SBCL may fail to derive a type of loop parameter, use polymorphic
operations and store:
(defun foo (eps)
(let ((x 2d0))
(loop while (> (abs (- (* x x) 2)) eps)
do (setq x (* 0.5d0 (+ x (/ 2d0 x)))))
x))
(DECLARE (DOUBLE-FLOAT X)) can help it (and SBCL can validate it -
so no run-time type checking will be performed) and so help to
avoid boxing. In fact, I think it's a rare case for ALIEN.
2. Operations on boxed ALIENs are very inefficient, if the type in
unknown. E.g.:
(defun foo (x)
(deref x))
uses the compiler and thus conses a lot. Declaring type of X
eliminates compiler call:
(defun foo (x)
(declare (type (alien (* int)) x))
(deref x))
> Maybe if I understood what %SAP-ALIEN actually did, I would be able to
> figure out how to hint the compiler properly. In particular, it's not
> clear to me at all why the following would happen. Is it because the
> length of the "string" pointed to by the alien pointer isn't known at
> compile time?
>
> CL-USER> (let ((x (make-alien char)))
> (print x)
> (free-alien x))
You call PRINT on X; it is a global function, compiled independently
of this code, so the compiler must use boxed represenation for its
argument.
(let ((x (make-alien char)))
(setf (deref x) 11)
(print (deref x))
(free-alien x))
Here all uses of X are in alien-related functions/macros, so, in
principle, SBCL could choose unboxed representation, but it does not.
Though for dynamic-extent aliens there is an alternative:
(with-alien ((x (array char)))
(setf (deref x) 11)
(print (deref x)))
Now there is no boxing :-)
--
Regards,
Alexey Dejneka
"Alas, the spheres of truth are less transparent than those of
illusion." -- L.E.J. Brouwer
|