[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Allocating closures on the stack
- To: info-mcl@ministry.cambridge.apple.com
- Subject: Allocating closures on the stack
- From: pazzani@pan.ICS.UCI.EDU (Michael Pazzani)
- Date: 27 Apr 94 04:42:43 GMT
- Newsgroups: comp.lang.lisp.mcl
A while back, I complained that MCL allocates closures on the
heap, making mapping function more expensive than loop, do, etc.
Now, I've finally decided to do something about it.
THE PROBLEM:
For example:
(defun p(x y)(position-if #'(lambda(e)(oddp (+ e y)))))
? (time (p '(1 2 3 ) 1))
(P '(1 2 3) 1) took 1 milliseconds (0.001 seconds) to run.
40 bytes of memory allocated.
A new closure is created and stored in the heap each time
p is called
(disassemble reveals that $SP-MKCLOSURE is called)
? (disassemble 'p)
0 (JSR_SUBPRIM $SP-TWO-ARGS-VPUSH)
4 (VPUSH '#<Anonymous Function #x8C6D6E>)
10 (VPUSH (VSP 4))
14 (SET_NARGS 2)
16 (JSR_SUBPRIM $SP-MKCLOSURE)
20 (MOVE.L ATEMP0 D1)
22 (MOVE.L (VSP 4) D0)
26 (SET_NARGS 2)
28 (SPOP VSP)
30 (JMP #'POSITION-IF)
A SOLUTION
(def-downward-funarg position-if 0)
creates a compiler macro that makes a flet, and
defines the function to have dynamic extent.. This calls
$SP-MKSTKCLOSURE which I presume puts the closure on the stack.
? (time (p '(1 2 3) 1))
(P '(1 2 3) 1) took 0 milliseconds (0.000 seconds) to run.
1
? (disassemble 'p)
0 (JSR_SUBPRIM $SP-TWO-ARGS-VPUSH)
4 (VPUSH '#<Compiled-function NOT-SO-ANONYMOUS-LAMBDA (Non-Global) #x8BC716>)
10 (VPUSH (VSP 4))
14 (SET_NARGS 2)
16 (JSR_SUBPRIM $SP-MKSTKCLOSURE)
20 (VPUSH ATEMP0)
22 (MOVE.L @VSP D1)
24 (MOVE.L (VSP 8) D0)
28 (SET_NARGS 2)
30 (MOVE.L '#<POSITION-IF Symbol Function Locative> ATEMP0)
36 (JSR_SUBPRIM $SP-MVPASS)
40 (JSR_SUBPRIM $SP-POPNLISPAREA)
44 (JMP_SUBPRIM $SP-NVALRET)
Here's the code for def-downward-funarg, and declarations
for many functions that take functional arguments. This reduced
the amount of space allocated by one system I used by about 10%
(since I use mapping functions a lot). If you can think of any
improvements, please let me know.
Michael Pazzani
Associate Professor
Department of Information and Computer Science
University of California
Irvine, CA 92717-3425
phone (714) 856-5888
fax (714) 856-4056
e-mail pazzani@ics.uci.edu
(defun function-lambda-p(x)
(and (consp x)
(eq (car x) 'function)
(consp (cadr x))
(eq (car (cadr x)) 'lambda)))
(defun create-compiler-macro(name functional-argument-position)
(cond ((gethash name ccl::*compiler-macros*)
(format t "~%;~A already defined." name) nil)
(t
`(define-compiler-macro ,name (&rest args)
(let ((funarg (nth ,functional-argument-position args)))
(if (function-lambda-p funarg)
(make-flet funarg ',name ,functional-argument-position args)
(cons ',name args)))))))
(defun make-flet(funarg new-name functional-argument-position args &aux (body (copy-list args)))
(setf (nth functional-argument-position body)
(list 'function 'not-so-anonymous-lambda))
`(flet ((not-so-anonymous-lambda ,(cadr (cadr funarg)) ,@(cddr (cadr funarg))))
(declare (dynamic-extent #'not-so-anonymous-lambda))
,(cons new-name body)))
(defmacro def-downward-funarg (name number)
(create-compiler-macro name number))
;(def-downward-funarg APPLY 0)
(def-downward-funarg FUNCALL 0)
;(def-downward-funarg MAPCAR 0)
;(def-downward-funarg MAPC 0)
(def-downward-funarg MAPCAN 0)
(def-downward-funarg MAPCON 0)
(def-downward-funarg MAP 1)
(def-downward-funarg MAPLIST 0)
(def-downward-funarg COUNT-IF 0)
(def-downward-funarg NSUBSTITUTE-IF-NOT 1)
(def-downward-funarg DELETE-IF-NOT 0)
(def-downward-funarg FIND-IF 0)
(def-downward-funarg NSUBSTITUTE-IF 1)
(def-downward-funarg MEMBER-IF-NOT 0)
(def-downward-funarg DELETE-IF 0)
(def-downward-funarg SUBST-IF 1)
(def-downward-funarg SUBST-IF-NOT 1)
(def-downward-funarg NSUBST-IF-NOT 1)
(def-downward-funarg REMOVE-IF 0)
(def-downward-funarg SUBSTITUTE-IF-NOT 1)
(def-downward-funarg POSITION-IF-NOT 0)
(def-downward-funarg POSITION-IF 0)
(def-downward-funarg NSUBST-IF 1)
(def-downward-funarg SUBSTITUTE-IF 1)
(def-downward-funarg REMOVE-IF-NOT 0)
(def-downward-funarg MEMBER-IF 0)
(def-downward-funarg FIND-IF-NOT 0)
(def-downward-funarg COUNT-IF-NOT 0)
(def-downward-funarg REDUCE 0)
;(def-downward-funarg NOTANY 0)
;(def-downward-funarg NOTEVERY 0)
(def-downward-funarg RASSOC-IF-NOT 0)
(def-downward-funarg RASSOC-IF 0)
(def-downward-funarg ASSOC-IF-NOT 0)
(def-downward-funarg ASSOC-IF 0)
(def-downward-funarg STABLE-SORT 1)
;(def-downward-funarg SOME 0)
(def-downward-funarg SORT 1)
(def-downward-funarg MERGE 3)
;(def-downward-funarg EVERY 0)
#|
(do-symbols (s) ;try predicate and test also
(when (member 'function (arglist s))
(format t "~%(def-downward-funarg ~a ~a)"
s (position 'function (arglist s) ))))
(defun p(x y)(position-if #'(lambda(e)(oddp (+ e y))) x))
(time (p '(1 2 3 ) 1))
|#