1 ;;;; basic environmental stuff
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from software originally released by Xerox
7 ;;;; Corporation. Copyright and release statements follow. Later modifications
8 ;;;; to the software are in the public domain and are provided with
9 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
12 ;;;; copyright information from original PCL sources:
14 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
15 ;;;; All rights reserved.
17 ;;;; Use and copying of this software and preparation of derivative works based
18 ;;;; upon this software are permitted. Any distribution of this software or
19 ;;;; derivative works must comply with all applicable United States export
22 ;;;; This software is made available AS IS, and Xerox Corporation makes no
23 ;;;; warranty about the software, its performance or its conformity to any
28 ;;; FIXME: This stuff isn't part of the ANSI spec, and isn't even
29 ;;; exported from PCL, but it looks as though it might be useful,
30 ;;; so I don't want to just delete it. Perhaps it should go in
31 ;;; a "contrib" directory eventually?
34 (defun parse-method-or-spec (spec &optional
(errorp t
))
35 (let (gf method name temp
)
38 gf
(method-generic-function method
)
39 temp
(and gf
(generic-function-name gf
))
41 (make-method-spec temp
42 (method-qualifiers method
)
44 (method-specializers method
)))
45 (make-symbol (format nil
"~S" method
))))
46 (multiple-value-bind (gf-spec quals specls
)
47 (parse-defmethod spec)
48 (and (setq gf
(and (or errorp
(fboundp gf-spec
))
49 (gdefinition gf-spec
)))
50 (let ((nreq (compute-discriminating-function-arglist-info gf
)))
51 (setq specls
(append (parse-specializers specls
)
52 (make-list (- nreq
(length specls
))
56 (setq method
(get-method gf quals specls errorp
))
59 gf-spec quals
(unparse-specializers specls
))))))))
60 (values gf method name
)))
62 ;;; TRACE-METHOD and UNTRACE-METHOD accept method specs as arguments. A
63 ;;; method-spec should be a list like:
64 ;;; (<generic-function-spec> qualifiers* (specializers*))
65 ;;; where <generic-function-spec> should be either a symbol or a list
66 ;;; of (SETF <symbol>).
68 ;;; For example, to trace the method defined by:
70 ;;; (defmethod foo ((x spaceship)) 'ss)
74 ;;; (trace-method '(foo (spaceship)))
76 ;;; You can also provide a method object in the place of the method
77 ;;; spec, in which case that method object will be traced.
79 ;;; For UNTRACE-METHOD, if an argument is given, that method is untraced.
80 ;;; If no argument is given, all traced methods are untraced.
81 (defclass traced-method
(method)
82 ((method :initarg
:method
)
83 (function :initarg
:function
84 :reader method-function
)
85 (generic-function :initform nil
86 :accessor method-generic-function
)))
88 (defmethod method-lambda-list ((m traced-method
))
89 (with-slots (method) m
(method-lambda-list method
)))
91 (defmethod method-specializers ((m traced-method
))
92 (with-slots (method) m
(method-specializers method
)))
94 (defmethod method-qualifiers ((m traced-method
))
95 (with-slots (method) m
(method-qualifiers method
)))
97 (defmethod accessor-method-slot-name ((m traced-method
))
98 (with-slots (method) m
(accessor-method-slot-name method
)))
100 (defvar *traced-methods
* ())
102 (defun trace-method (spec &rest options
)
103 (multiple-value-bind (gf omethod name
)
104 (parse-method-or-spec spec
)
105 (let* ((tfunction (trace-method-internal (method-function omethod
)
108 (tmethod (make-instance 'traced-method
110 :function tfunction
)))
111 (remove-method gf omethod
)
112 (add-method gf tmethod
)
113 (pushnew tmethod
*traced-methods
*)
116 (defun untrace-method (&optional spec
)
117 (flet ((untrace-1 (m)
118 (let ((gf (method-generic-function m
)))
121 (add-method gf
(slot-value m
'method
))
122 (setq *traced-methods
* (remove m
*traced-methods
*))))))
123 (if (not (null spec
))
124 (multiple-value-bind (gf method
)
125 (parse-method-or-spec spec
)
126 (declare (ignore gf
))
127 (if (memq method
*traced-methods
*)
129 (error "~S is not a traced method?" method
)))
130 (dolist (m *traced-methods
*) (untrace-1 m
)))))
132 (defun trace-method-internal (ofunction name options
)
133 (eval `(untrace ,name
))
134 (setf (fdefinition name
) ofunction
)
135 (eval `(trace ,name
,@options
))
140 ;;;; Helper for slightly newer trace implementation, based on
141 ;;;; breakpoint stuff. The above is potentially still useful, so it's
142 ;;;; left in, commented.
144 ;;; (this turned out to be a roundabout way of doing things)
145 (defun list-all-maybe-method-names (gf)
147 (dolist (method (generic-function-methods gf
) (nreverse result
))
148 (let ((spec (nth-value 2 (parse-method-or-spec method
))))
150 (push (list* 'fast-method
(cdr spec
)) result
)))))
155 ;; Overwrite the old bootstrap non-generic MAKE-LOAD-FORM function with a
156 ;; shiny new generic function.
157 (fmakunbound 'make-load-form
)
158 (defgeneric make-load-form
(object &optional environment
))
160 ;; Link bootstrap-time how-to-dump-it information into the shiny new
162 (defmethod make-load-form ((obj sb-sys
:structure
!object
)
163 &optional
(env nil env-p
))
165 (sb-sys:structure
!object-make-load-form obj env
)
166 (sb-sys:structure
!object-make-load-form obj
)))
168 (defmethod make-load-form ((object wrapper
) &optional env
)
169 (declare (ignore env
))
170 (let ((pname (classoid-proper-name
171 (layout-classoid object
))))
173 (error "can't dump wrapper for anonymous class:~% ~S"
174 (layout-classoid object
)))
175 `(classoid-layout (find-classoid ',pname
))))
177 (defmethod make-load-form ((object structure-object
) &optional env
)
178 (declare (ignore env
))
179 (error "~@<don't know how to dump ~S (default ~S method called).~@>"
180 object
'make-load-form
))
182 (defmethod make-load-form ((object standard-object
) &optional env
)
183 (declare (ignore env
))
184 (error "~@<don't know how to dump ~S (default ~S method called).~@>"
185 object
'make-load-form
))
187 (defmethod make-load-form ((object condition
) &optional env
)
188 (declare (ignore env
))
189 (error "~@<don't know how to dump ~S (default ~S method called).~@>"
190 object
'make-load-form
))
192 (defun make-load-form-saving-slots (object &key
(slot-names nil slot-names-p
) environment
)
193 (declare (ignore environment
))
194 (let ((class (class-of object
)))
196 (dolist (slot (class-slots class
))
197 (let ((slot-name (slot-definition-name slot
)))
198 (when (or (memq slot-name slot-names
)
199 (and (not slot-names-p
)
200 (eq :instance
(slot-definition-allocation slot
))))
201 (if (slot-boundp-using-class class object slot
)
202 (let ((value (slot-value-using-class class object slot
)))
203 (if (typep object
'structure-object
)
204 ;; low-level but less noisy initializer form
205 ;; FIXME: why not go class->layout->info == dd?
206 (let* ((dd (find-defstruct-description
208 (dsd (find slot-name
(dd-slots dd
)
210 (inits `(,(slot-setter-lambda-form dd dsd
)
212 (inits `(setf (slot-value ,object
',slot-name
) ',value
))))
213 (inits `(slot-makunbound ,object
',slot-name
))))))
214 (values `(allocate-instance (find-class ',(class-name class
)))
215 `(progn ,@(inits))))))