x86-64/allocate-list-on-stack: encode large immediates.
[sbcl.git] / tests / unwind-to-frame-and-call.impure.lisp
bloba6eca0905c5118a92c0cafa814bd2f172cc6e2cf
1 ;;;; This file is for testing UNWIND-TO-FRAME-AND-CALL, used for
2 ;;;; implementing RESTART-FRAME and RETURN-FROM-FRAME in the debugger.
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; While most of SBCL is derived from the CMU CL system, the test
8 ;;;; files (like this one) were written from scratch after the fork
9 ;;;; from CMU CL.
10 ;;;;
11 ;;;; This software is in the public domain and is provided with
12 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
13 ;;;; more information.
15 ;;; The debugger doesn't have any native knowledge of the interpreter
16 (when (eq sb-ext:*evaluator-mode* :interpret)
17 (invoke-restart 'run-tests::skip-file))
19 (declaim (optimize debug))
21 (defun return-from-frame (frame-name &rest values)
22 (let ((frame (sb-di::top-frame)))
23 (loop until (equal frame-name
24 (sb-debug::frame-call frame))
25 do (setf frame (sb-di::frame-down frame)))
26 (assert frame)
27 (assert (sb-debug::frame-has-debug-tag-p frame))
28 (sb-debug::unwind-to-frame-and-call frame
29 (lambda ()
30 (values-list values)))))
32 (defun restart-frame (frame-name)
33 (let ((frame (sb-di::top-frame)))
34 (loop until (equal (sb-debug::frame-call frame)
35 frame-name)
36 do (setf frame (sb-di::frame-down frame)))
37 (assert frame)
38 (assert (sb-debug::frame-has-debug-tag-p frame))
39 (let* ((call-list (sb-debug::frame-call-as-list frame call-arguments-limit))
40 (fun (fdefinition (car call-list))))
41 (sb-debug::unwind-to-frame-and-call frame
42 (lambda ()
43 (apply fun (cdr call-list)))))))
45 (defvar *foo*)
46 (defvar *a*)
47 (defvar *b*)
48 (defvar *c*)
51 ;;;; Test RESTART-FRAME
53 (define-condition restart-condition () ())
55 (defvar *count* 0)
57 (defun restart/special (*foo*)
58 (incf *count*)
59 (unless *a*
60 (setf *a* t)
61 (signal 'restart-condition))
62 *foo*)
64 (defun restart/optional-special (&optional (*foo* 1))
65 (incf *count*)
66 (unless *a*
67 (setf *a* t)
68 (signal 'restart-condition))
69 *foo*)
71 (defun restart/normal (foo)
72 (incf *count*)
73 (unless *a*
74 (setf *a* t)
75 (signal 'restart-condition))
76 foo)
78 #+win32
79 (defun decline ()
80 ;; these tests currently fail no matter whether threads are enabled or
81 ;; not, but on threaded builds the failure mode is particularly
82 ;; unfortunate. As a workaround, opt out of running the test.
83 #+sb-thread
84 (error "this test fails with exception 0xc0000029 ~
85 (STATUS_INVALID_UNWIND_TARGET), from which we cannot currently ~
86 recover"))
88 (defun test-restart (name)
89 #+win32 (decline)
90 (setf *a* nil)
91 (let ((*foo* 'x))
92 (let ((*foo* 'y)
93 (*count* 0))
94 (handler-bind ((restart-condition (lambda (c)
95 (declare (ignore c))
96 (restart-frame name))))
97 (assert (eql (funcall name 1) 1))
98 (assert (eql *count* 2))))
99 ;; Check that the binding stack was correctly unwound.
100 (assert (eql *foo* 'x))))
102 (with-test (:name (:restart-frame :special) :fails-on :win32)
103 (test-restart 'restart/special))
105 (with-test (:name (:restart-frame :optional-special) :fails-on :win32)
106 (test-restart 'restart/optional-special))
108 (with-test (:name (:restart-frame :normal) :fails-on :win32)
109 (test-restart 'restart/normal))
112 ;;;; Test RETURN-FROM-FRAME with normal functions
114 (define-condition return-condition () ())
116 (defun return/special (*foo*)
117 (unless *a*
118 (setf *a* t)
119 (signal 'return-condition))
120 *foo*)
122 (defun return/optional-special (&optional (*foo* 1))
123 (unless *a*
124 (setf *a* t)
125 (signal 'return-condition))
126 *foo*)
128 (defun return/normal (foo)
129 (unless *a*
130 (setf *a* t)
131 (signal 'return-condition))
132 foo)
134 (defun do-signal ()
135 (signal 'return-condition))
137 (defun return/catch (foo)
138 (catch 'y
139 (do-signal))
140 foo)
142 (defun test-return (name)
143 #+win32 (decline)
144 (setf *a* nil)
145 (let ((*foo* 'x))
146 (let ((*foo* 'y))
147 (handler-bind ((return-condition (lambda (c)
148 (declare (ignore c))
149 (return-from-frame name 1 2 3 4))))
150 (assert (equal (multiple-value-list (funcall name 0))
151 (list 1 2 3 4)))))
152 ;; Check that the binding stack was correctly unwound.
153 (assert (eql *foo* 'x))))
155 (with-test (:name (:return-from-frame :special) :fails-on :win32)
156 (test-return 'return/special))
158 (with-test (:name (:return-from-frame :optional-special) :fails-on :win32)
159 (test-return 'return/optional-special))
161 (with-test (:name (:return-from-frame :normal) :fails-on :win32)
162 (test-return 'return/normal))
164 (defun throw-y () (throw 'y 'y))
166 ;; Check that *CURRENT-CATCH-BLOCK* was correctly restored.
167 (with-test (:name :current-catch-block-restored :fails-on :win32)
168 (assert (eql (catch 'y
169 (test-return 'return/catch)
170 (throw-y))
171 'y)))
174 ;;;; Test RETURN-FROM-FRAME with local functions
176 (define-condition in-a () ())
177 (define-condition in-b () ())
179 (defun locals ()
180 (flet ((a ()
181 (signal 'in-a)
182 (values 1 2))
183 (b ()
184 (signal 'in-b)
186 (setf *a* (multiple-value-list (a)))
187 (setf *b* (multiple-value-list (b)))))
189 (defun hairy-locals ()
190 (let ((*c* :bad))
191 (flet ((a (&optional *c*)
192 (signal 'in-a)
193 (values 1 2))
194 (b (&key *c*)
195 (signal 'in-b)
197 ;; Ensure that A and B actually appear in the backtrace; the
198 ;; compiler for some reason likes to optimize away single-use
199 ;; local functions with hairy lambda-lists even on high debug
200 ;; levels.
201 (setf *a* (a :good))
202 (setf *b* (b :*c* :good))
203 ;; Do the real tests
204 (setf *a* (multiple-value-list (a :good)))
205 (setf *b* (multiple-value-list (b :*c* :good))))))
207 (defun test-locals (name)
208 #+win32 (decline)
209 (handler-bind ((in-a (lambda (c)
210 (declare (ignore c))
211 (return-from-frame `(flet a :in ,name) 'x 'y)))
212 (in-b (lambda (c)
213 (declare (ignore c))
214 (return-from-frame `(flet b :in ,name) 'z))))
215 (funcall name))
216 ;; We're intentionally not testing for returning a different amount
217 ;; of values than the local functions are normally returning. It's
218 ;; hard to think of practical cases where that'd be useful, but
219 ;; allowing it (as in the old fully CATCH-based implementation of
220 ;; UNWIND-TO-FRAME-AND-CALL) will make it harder for the compiler to
221 ;; work well.
222 (let ((*foo* 'x))
223 (let ((*foo* 'y))
224 (assert (equal *a* '(x y)))
225 (assert (equal *b* '(z))))
226 (assert (eql *foo* 'x))))
228 (with-test (:name (:return-from-frame :local-function) :fails-on :win32)
229 (test-locals 'locals))
231 (with-test (:name (:return-from-frame :hairy-local-function) :fails-on :win32)
232 (test-locals 'hairy-locals))
235 ;;;; Test RETURN-FROM-FRAME with anonymous functions
237 (define-condition anon-condition () ())
239 (defparameter *anon-1*
240 (lambda (foo)
241 (signal 'anon-condition)
242 foo))
244 (defparameter *anon-2*
245 (lambda (*foo*)
246 (signal 'anon-condition)
247 *foo*))
249 (defun make-anon-3 ()
250 (let ((a (lambda (foo)
251 (signal 'anon-condition)
252 foo)))
253 (funcall a 1)
256 (defun make-anon-4 ()
257 (let ((a (lambda (*foo*)
258 (signal 'anon-condition)
259 *foo*)))
260 (funcall a 1)
263 (defparameter *anon-3* (make-anon-3))
264 (defparameter *anon-4* (make-anon-4))
266 (defun test-anon (fun var-name &optional in)
267 #+win32 (decline)
268 (handler-bind ((anon-condition (lambda (c)
269 (declare (ignore c))
270 (return-from-frame
271 `(lambda (,var-name) ,@(when in `(:in ,in)))
272 'x 'y))))
273 (let ((*foo* 'x))
274 (let ((*foo* 'y))
275 (assert (equal (multiple-value-list (funcall fun 1))
276 '(x y)))
277 (assert (eql *foo* 'y)))
278 (assert (eql *foo* 'x)))))
280 (defvar *p* (namestring (if sb-c::*merge-pathnames* *load-truename* *load-pathname*)))
282 (with-test (:name (:return-from-frame :anonymous :toplevel) :fails-on :win32)
283 (test-anon *anon-1* 'foo *p*))
285 (with-test (:name (:return-from-frame :anonymous :toplevel-special)
286 :fails-on :win32)
287 (test-anon *anon-2* '*foo* *p*))
289 (with-test (:name (:return-from-frame :anonymous) :fails-on :win32)
290 (test-anon *anon-3* 'foo 'make-anon-3))
292 (with-test (:name (:return-from-frame :anonymous :special) :fails-on :win32)
293 (test-anon *anon-4* '*foo* 'make-anon-4))
296 ;;;; Test that unwind cleanups are executed
298 (defvar *unwind-state* nil)
299 (defvar *signal* nil)
301 (defun unwind-1 ()
302 (unwind-protect
303 (when *signal*
304 (signal 'return-condition))
305 (push :unwind-1 *unwind-state*)))
307 (defun unwind-2 ()
308 (unwind-protect
309 (unwind-1)
310 (push :unwind-2 *unwind-state*)))
312 (defun test-unwind (fun wanted)
313 #+win32 (decline)
314 (handler-bind ((return-condition (lambda (c)
315 (declare (ignore c))
316 (return-from-frame fun
317 'x 'y))))
318 (dolist (*signal* (list nil t))
319 (let ((*foo* 'x)
320 (*unwind-state* nil))
321 (let ((*foo* 'y))
322 (if *signal*
323 (assert (equal (multiple-value-list (funcall fun))
324 '(x y)))
325 (funcall fun))
326 (assert (equal *unwind-state* wanted))
327 (assert (eql *foo* 'y)))
328 (assert (eql *foo* 'x))))))
330 (with-test (:name :test-unwind-1 :fails-on :win32)
331 (test-unwind 'unwind-1 '(:unwind-1)))
332 (with-test (:name :test-unwind-2 :fails-on :win32)
333 (test-unwind 'unwind-2 '(:unwind-2 :unwind-1)))
335 ;;; Regression in 1.0.10.47 reported by James Knight
337 (defun inner1 (tla)
338 (zerop tla))
340 (declaim (inline inline-fun))
341 (defun inline-fun (tla)
342 (or (inner1 tla)
343 (inner1 tla)))
345 (defun foo (predicate)
346 (funcall predicate 2))
348 (defun test ()
349 (let ((blah (foo #'inline-fun)))
350 (inline-fun 3)))
352 (with-test (:name (:debug-instrumentation :inline/xep))
353 (test))