1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from software originally released by Xerox
5 ;;;; Corporation. Copyright and release statements follow. Later modifications
6 ;;;; to the software are in the public domain and are provided with
7 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
10 ;;;; copyright information from original PCL sources:
12 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
13 ;;;; All rights reserved.
15 ;;;; Use and copying of this software and preparation of derivative works based
16 ;;;; upon this software are permitted. Any distribution of this software or
17 ;;;; derivative works must comply with all applicable United States export
20 ;;;; This software is made available AS IS, and Xerox Corporation makes no
21 ;;;; warranty about the software, its performance or its conformity to any
26 ;;; GET-FUN is the main user interface to this code. It is like
27 ;;; COMPILE, only more efficient. It achieves this efficiency by
28 ;;; reducing the number of times that the compiler needs to be called.
29 ;;; Calls to GET-FUN in which the lambda forms differ only by
30 ;;; constants can use the same piece of compiled code. (For example,
31 ;;; dispatch dfuns and combined method functions can often be shared,
32 ;;; if they differ only by referring to different methods.)
34 ;;; If GET-FUN is called with a lambda expression only, it will return
35 ;;; a corresponding function. The optional constant-converter argument
36 ;;; can be a function which will be called to convert each constant appearing
37 ;;; in the lambda to whatever value should appear in the function.
39 ;;; There are three internal functions which operate on the lambda argument
41 ;;; COMPUTE-TEST converts the lambda into a key to be used for lookup,
42 ;;; COMPUTE-CODE is used by GET-NEW-FUN-GENERATOR-INTERNAL to
43 ;;; generate the actual lambda to be compiled, and
44 ;;; COMPUTE-CONSTANTS is used to generate the argument list that is
45 ;;; to be passed to the compiled function.
47 (defun get-fun (lambda &optional
48 (test-converter #'default-test-converter
)
49 (code-converter #'default-code-converter
)
50 (constant-converter #'default-constant-converter
))
51 (function-apply (get-fun-generator lambda test-converter code-converter
)
52 (compute-constants lambda constant-converter
)))
54 (defun get-fun1 (lambda &optional
55 (test-converter #'default-test-converter
)
56 (code-converter #'default-code-converter
)
57 (constant-converter #'default-constant-converter
))
59 (get-fun-generator lambda test-converter code-converter
))
60 (compute-constants lambda constant-converter
)))
62 (defun default-constantp (form)
63 (constant-typep form
'(not (or symbol fixnum cons
))))
65 (defun default-test-converter (form)
66 (if (default-constantp form
)
70 (defun default-code-converter (form)
71 (if (default-constantp form
)
72 (let ((gensym (gensym))) (values gensym
(list gensym
)))
75 (defun default-constant-converter (form)
76 (if (default-constantp form
)
77 (list (constant-form-value form
))
80 (defstruct (fgen (:constructor make-fgen
(gensyms generator generator-lambda system
)))
86 ;;; *FGENS* stores all the function generators we have so far. Each
87 ;;; element is a FGEN structure as implemented below. Don't ever touch this
88 ;;; list by hand, use LOOKUP-FGEN, and ENSURE-FGEN.
89 (defvar *fgens
* (make-hash-table :test
#'equal
:synchronized t
))
91 (defun ensure-fgen (test gensyms generator generator-lambda system
)
92 (with-locked-hash-table (*fgens
*)
93 (let ((old (lookup-fgen test
)))
95 (setf (fgen-generator old
) generator
)
96 (unless (fgen-system old
)
97 (setf (fgen-system old
) system
)))
99 (setf (gethash test
*fgens
*)
100 (make-fgen gensyms generator generator-lambda system
)))))))
102 (defun lookup-fgen (test)
103 (gethash test
*fgens
*))
105 (defun get-fun-generator (lambda test-converter code-converter
)
106 (let* ((test (compute-test lambda test-converter
))
107 (fgen (lookup-fgen test
)))
109 (fgen-generator fgen
)
110 (get-new-fun-generator lambda test code-converter
))))
112 (defun get-new-fun-generator (lambda test code-converter
)
113 (multiple-value-bind (code gensyms
) (compute-code lambda code-converter
)
114 (let ((generator-lambda `(lambda ,gensyms
(function ,code
))))
115 (let ((generator (compile nil generator-lambda
)))
116 (ensure-fgen test gensyms generator generator-lambda nil
)
119 (defun compute-test (lambda test-converter
)
120 (let ((*walk-form-expand-macros-p
* t
))
127 (let ((converted (funcall test-converter f
)))
128 (values converted
(neq converted f
))))))))
130 (defun compute-code (lambda code-converter
)
131 (let ((*walk-form-expand-macros-p
* t
)
133 (values (walk-form lambda
139 (multiple-value-bind (converted gens
)
140 (funcall code-converter f
)
142 (setq gensyms
(append gensyms gens
)))
143 (values converted
(neq converted f
))))))
146 (defun compute-constants (lambda constant-converter
)
147 (let ((*walk-form-expand-macros-p
* t
) ; doesn't matter here.
155 (let ((consts (funcall constant-converter f
)))
158 (setq collect
(append collect consts
))
163 (defmacro precompile-function-generators
(&optional system
)
165 (with-locked-hash-table (*fgens
*)
166 (maphash (lambda (test fgen
)
167 (when (or (null (fgen-system fgen
))
168 (eq (fgen-system fgen
) system
))
170 (setf (fgen-system fgen
) system
))
173 ',(fgen-gensyms fgen
)
174 (function ,(fgen-generator-lambda fgen
))
175 ',(fgen-generator-lambda fgen
)