Fix more C warnings
[sbcl.git] / src / compiler / x86-64 / nlx.lisp
blob331a3dbf7cf2317e61053306789873efd730d1ef
1 ;;;; the definition of non-local exit for the x86 VM
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB-VM")
14 ;;; Make a TN for the argument count passing location for a non-local entry.
15 (defun make-nlx-entry-arg-start-location ()
16 (make-wired-tn *fixnum-primitive-type* any-reg-sc-number rbx-offset))
18 (defun catch-block-ea (tn &optional (offset 0))
19 (aver (sc-is tn catch-block))
20 (ea (frame-byte-offset (- (+ -1 (tn-offset tn) catch-block-size) offset)) rbp-tn))
22 (defun unwind-block-ea (tn &optional (offset 0))
23 (aver (sc-is tn unwind-block))
24 (ea (frame-byte-offset (- (+ -1 (tn-offset tn) unwind-block-size offset) offset)) rbp-tn))
26 ;;;; Save and restore dynamic environment.
27 (define-vop (current-stack-pointer)
28 (:results (res :scs (any-reg control-stack)))
29 (:generator 1
30 (move res rsp-tn)))
32 (define-vop (current-binding-pointer)
33 (:results (res :scs (any-reg descriptor-reg)))
34 (:generator 1
35 (load-binding-stack-pointer res)))
37 ;;;; unwind block hackery
39 ;;; Compute the address of the catch block from its TN, then store into the
40 ;;; block the current Fp, Env, Unwind-Protect, and the entry PC.
41 #+sb-thread
42 (progn
43 ;; MOVAPD instruction faults if not properly aligned
44 (assert (evenp (/ (info :variable :wired-tls '*binding-stack-pointer*) n-word-bytes)))
45 (assert (= (- (info :variable :wired-tls '*current-catch-block*)
46 (info :variable :wired-tls '*binding-stack-pointer*))
47 n-word-bytes))
48 (assert (= (- unwind-block-current-catch-slot unwind-block-bsp-slot) 1)))
50 (define-vop (make-unwind-block)
51 (:args (tn))
52 (:info entry-label)
53 (:temporary (:sc unsigned-reg) temp)
54 #+sb-thread
55 (:temporary (:sc complex-double-reg) xmm-temp)
56 (:results (block :scs (any-reg)))
57 (:vop-var vop)
58 (:generator 22
59 (inst lea block (unwind-block-ea tn))
60 (load-tl-symbol-value temp *current-unwind-protect-block*)
61 (storew temp block unwind-block-uwp-slot)
62 (storew rbp-tn block unwind-block-cfp-slot)
63 (inst lea temp (rip-relative-ea entry-label))
64 (storew temp block unwind-block-entry-pc-slot)
65 #+sb-thread
66 (let ((bsp (info :variable :wired-tls '*binding-stack-pointer*)))
67 (inst movapd xmm-temp (thread-tls-ea bsp))
68 (inst movupd (ea (* unwind-block-bsp-slot n-word-bytes) block) xmm-temp))
69 #-sb-thread
70 (progn
71 (load-binding-stack-pointer temp)
72 (storew temp block unwind-block-bsp-slot)
73 (load-tl-symbol-value temp *current-catch-block*)
74 (storew temp block unwind-block-current-catch-slot))))
76 ;;; like MAKE-UNWIND-BLOCK, except that we also store in the specified
77 ;;; tag, and link the block into the CURRENT-CATCH list
78 (define-vop (make-catch-block)
79 (:args (tn)
80 (tag :scs (any-reg descriptor-reg) :to (:result 1)))
81 (:info entry-label)
82 (:results (block :scs (any-reg)))
83 (:temporary (:sc descriptor-reg) temp)
84 #+sb-thread
85 (:temporary (:sc complex-double-reg) xmm-temp)
86 (:vop-var vop)
87 (:generator 44
88 (inst lea block (catch-block-ea tn))
89 (load-tl-symbol-value temp *current-unwind-protect-block*)
90 (storew temp block catch-block-uwp-slot)
91 (storew rbp-tn block catch-block-cfp-slot)
92 (inst lea temp (rip-relative-ea entry-label))
93 (storew temp block catch-block-entry-pc-slot)
94 (storew tag block catch-block-tag-slot)
95 #+sb-thread
96 (let ((bsp #1=(info :variable :wired-tls '*binding-stack-pointer*)))
97 #.(assert (and (= (- (info :variable :wired-tls '*current-catch-block*) #1#) n-word-bytes)
98 (= (- catch-block-previous-catch-slot catch-block-bsp-slot) 1)))
99 (inst movapd xmm-temp (thread-tls-ea bsp))
100 (inst movupd (ea (* catch-block-bsp-slot n-word-bytes) block) xmm-temp)
101 (store-tl-symbol-value block *current-catch-block*))
102 #-sb-thread
103 (progn
104 (load-tl-symbol-value temp *current-catch-block*)
105 (storew temp block catch-block-previous-catch-slot)
106 (store-tl-symbol-value block *current-catch-block*)
107 (load-binding-stack-pointer temp)
108 (storew temp block catch-block-bsp-slot))))
110 ;;; Just set the current unwind-protect to UWP. This instantiates an
111 ;;; unwind block as an unwind-protect.
112 (define-vop (set-unwind-protect)
113 (:args (uwp :scs (any-reg)))
114 (:generator 7
115 (store-tl-symbol-value uwp *current-unwind-protect-block*)))
117 (define-vop (%catch-breakup)
118 (:args (current-block))
119 (:temporary (:sc unsigned-reg) block)
120 (:policy :fast-safe)
121 (:generator 17
122 (inst mov block (catch-block-ea current-block
123 catch-block-previous-catch-slot))
124 (store-tl-symbol-value block *current-catch-block*)))
126 (define-vop (%unwind-protect-breakup)
127 (:args (current-block))
128 (:temporary (:sc unsigned-reg) block)
129 (:policy :fast-safe)
130 (:generator 17
131 (inst mov block (unwind-block-ea current-block
132 unwind-block-uwp-slot))
133 (store-tl-symbol-value block *current-unwind-protect-block*)))
135 ;;;; NLX entry VOPs
136 (define-vop (nlx-entry)
137 ;; Note: we can't list an sc-restriction, 'cause any load vops would
138 ;; be inserted before the return-pc label.
139 (:args (sp)
140 (start)
141 (count))
142 (:results (values :more t))
143 (:temporary (:sc descriptor-reg) move-temp)
144 (:info label nvals)
145 (:save-p :force-to-stack)
146 (:vop-var vop)
147 (:generator 30
148 (emit-label label)
149 (note-this-location vop :non-local-entry)
150 (cond ((zerop nvals))
151 ((= nvals 1)
152 (let ((no-values (gen-label)))
153 (inst mov (tn-ref-tn values) nil-value)
154 (inst test rcx-tn rcx-tn)
155 (inst jmp :z no-values)
156 (loadw (tn-ref-tn values) start -1)
157 (emit-label no-values)))
159 ;; FIXME: this is mostly copied from
160 ;; DEFAULT-UNKNOWN-VALUES.
161 (collect ((defaults))
162 (do ((i 0 (1+ i))
163 (tn-ref values (tn-ref-across tn-ref)))
164 ((null tn-ref))
165 (let ((default-lab (gen-label))
166 (tn (tn-ref-tn tn-ref))
167 (first-stack-arg-p (= i register-arg-count)))
168 (defaults (cons default-lab (cons tn first-stack-arg-p)))
169 (inst cmp count (fixnumize i))
170 (inst jmp :le default-lab)
171 (when first-stack-arg-p
172 (storew rdx-tn rbx-tn -1))
173 (sc-case tn
174 ((descriptor-reg any-reg)
175 (loadw tn start (frame-word-offset (+ sp->fp-offset i))))
176 ((control-stack)
177 (loadw move-temp start
178 (frame-word-offset (+ sp->fp-offset i)))
179 (inst mov tn move-temp)))))
180 (let ((defaulting-done (gen-label)))
181 (emit-label defaulting-done)
182 (assemble (:elsewhere)
183 (dolist (default (defaults))
184 (emit-label (car default))
185 (when (cddr default)
186 (inst push rdx-tn))
187 (inst mov (second default) nil-value))
188 (inst jmp defaulting-done))))))
189 (inst mov rsp-tn sp)))
191 (define-vop (nlx-entry-single)
192 (:args (sp)
193 (start))
194 (:results (res :from :load))
195 (:info label)
196 (:save-p :force-to-stack)
197 (:vop-var vop)
198 (:generator 30
199 (emit-label label)
200 (note-this-location vop :non-local-entry)
201 (inst mov res start)
202 (inst mov rsp-tn sp)))
204 (define-vop (nlx-entry-multiple)
205 (:args (top :target result
206 :scs (any-reg))
207 (source :to :save)
208 (count :target rcx))
209 (:info label)
210 (:before-load
211 (emit-label label)
212 (note-this-location vop :non-local-entry))
213 (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 2)) rcx)
214 (:temporary (:sc unsigned-reg) loop-index temp)
215 (:results (result :scs (any-reg))
216 (num :scs (any-reg control-stack)))
217 (:save-p :force-to-stack)
218 (:arg-refs top-tn-ref)
219 (:vop-var vop)
220 (:generator 30
221 ;; The 'top' arg contains the %esp value saved at the time the
222 ;; catch block was created and points to where the thrown values
223 ;; should sit.
224 (if (eq (tn-kind result) :unused)
225 (setf result top)
226 (move result top))
228 (unless (eq (tn-kind num) :unused)
229 (move num count))
230 (move rcx count)
231 (zeroize loop-index)
232 (inst test rcx rcx)
233 (inst jmp :z DONE)
234 LOOP
235 (inst sub loop-index n-word-bytes)
236 (inst mov temp (ea source loop-index))
237 (inst mov (ea result loop-index) temp)
239 (inst sub rcx (fixnumize 1))
240 (inst jmp :nz LOOP)
241 DONE
242 ;; Reset the CSP at last moved arg.
243 (inst lea rsp-tn (ea result loop-index))))
246 ;;; This VOP is just to force the TNs used in the cleanup onto the stack.
247 (define-vop (uwp-entry)
248 (:info label)
249 (:save-p :force-to-stack)
250 (:vop-var vop)
251 (:generator 0
252 (emit-label label)
253 (note-this-location vop :non-local-entry)))
255 (define-vop (uwp-entry-block)
256 (:info label)
257 (:save-p :force-to-stack)
258 (:results (block))
259 (:vop-var vop)
260 (:generator 0
261 (emit-label label)
262 (note-this-location vop :non-local-entry)
263 ;; Get the saved block in UNWIND
264 (inst mov block (ea (* 3 n-word-bytes) rsp-tn))))
266 (define-vop (unwind-to-frame-and-call)
267 (:args (ofp :scs (descriptor-reg))
268 (uwp :scs (descriptor-reg))
269 (function :scs (descriptor-reg) :to :load :target saved-function)
270 (bsp :scs (any-reg descriptor-reg))
271 (catch-block :scs (any-reg descriptor-reg)))
272 (:arg-types system-area-pointer system-area-pointer t t t)
273 (:temporary (:sc sap-reg) temp)
274 (:temporary (:sc descriptor-reg :offset rbx-offset) saved-function)
275 (:temporary (:sc unsigned-reg :offset rax-offset) block)
276 (:temporary (:sc unsigned-reg :offset r11-offset) extra-temp-reg)
277 (:vop-var vop)
278 (:generator 22
279 ;; Store the function into a non-stack location, since we'll be
280 ;; unwinding the stack and destroying register contents before we
281 ;; use it. It turns out that RBX is preserved as part of the
282 ;; normal multiple-value handling of an unwind, so use that.
283 (move saved-function function)
285 ;; Allocate space for magic UWP block.
286 (inst sub rsp-tn (* unwind-block-size n-word-bytes))
287 ;; Set up magic catch / UWP block.
288 (move block rsp-tn)
289 (loadw temp uwp sap-pointer-slot other-pointer-lowtag)
290 (storew temp block unwind-block-uwp-slot)
291 (loadw temp ofp sap-pointer-slot other-pointer-lowtag)
292 (storew temp block unwind-block-cfp-slot)
294 (inst lea extra-temp-reg (rip-relative-ea entry-label))
295 (storew extra-temp-reg block unwind-block-entry-pc-slot)
296 (storew bsp block unwind-block-bsp-slot)
297 (storew catch-block block unwind-block-current-catch-slot)
299 ;; Run any required UWPs.
300 (invoke-asm-routine 'jmp 'unwind vop)
301 ENTRY-LABEL
303 ;; Move our saved function to where we want it now.
304 (move block saved-function)
306 ;; No parameters
307 (zeroize rcx-tn)
309 ;; Clear the stack
310 (inst lea rsp-tn (ea (* (- sp->fp-offset 3) n-word-bytes) rbp-tn))
312 ;; Push the return-pc so it looks like we just called.
313 (pushw rbp-tn (frame-word-offset return-pc-save-offset))
315 ;; Call it
316 (inst jmp (ea (- (* closure-fun-slot n-word-bytes) fun-pointer-lowtag)
317 block))))