More robust undefined restarts.
[sbcl.git] / src / compiler / x86-64 / cell.lisp
blob1041d0af8349b7bc0139fabdad2bbf39202cd729
1 ;;;; various primitive memory access VOPs 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 ;;;; data object ref/set stuff
16 (define-vop (slot)
17 (:args (object :scs (descriptor-reg)))
18 (:info name offset lowtag)
19 (:ignore name)
20 (:results (result :scs (descriptor-reg any-reg)))
21 (:generator 1
22 (loadw result object offset lowtag)))
24 (define-vop (set-slot)
25 (:args (object :scs (descriptor-reg))
26 (value :scs (descriptor-reg any-reg immediate)))
27 (:temporary (:sc descriptor-reg) temp)
28 (:info name offset lowtag)
29 ;(:ignore name)
30 (:results)
31 (:generator 1
32 (progn name) ; ignore it
33 (generate-set-slot object value temp offset lowtag)))
35 (defun generate-set-slot (object value temp offset lowtag)
36 (if (sc-is value immediate)
37 (move-immediate (make-ea :qword
38 :base object
39 :disp (- (* offset n-word-bytes)
40 lowtag))
41 (encode-value-if-immediate value)
42 temp)
43 ;; Else, value not immediate.
44 (storew value object offset lowtag)))
46 ;; INIT-SLOT has to know about the :COMPACT-INSTANCE-HEADER feature.
47 (define-vop (init-slot set-slot)
48 (:generator 1
49 (progn name)
50 (if (or #!+compact-instance-header
51 (and (eq name '%make-structure-instance) (eql offset :layout)))
52 ;; The layout is in the upper half of the header word.
53 ;; FIXME: It would be nice if FIXED-ALLOC could write the header word
54 ;; in one shot, but this is an acceptable workaround.
55 (inst mov
56 (make-ea :dword :base object :disp (- 4 instance-pointer-lowtag))
57 (reg-in-size value :dword))
58 (generate-set-slot object value temp offset lowtag))))
60 (define-vop (compare-and-swap-slot)
61 (:args (object :scs (descriptor-reg) :to :eval)
62 (old :scs (descriptor-reg any-reg) :target rax)
63 (new :scs (descriptor-reg any-reg)))
64 (:temporary (:sc descriptor-reg :offset rax-offset
65 :from (:argument 1) :to :result :target result)
66 rax)
67 (:info name offset lowtag)
68 (:ignore name)
69 (:results (result :scs (descriptor-reg any-reg)))
70 (:generator 5
71 (move rax old)
72 (inst cmpxchg (make-ea :qword :base object
73 :disp (- (* offset n-word-bytes) lowtag))
74 new :lock)
75 (move result rax)))
77 ;;;; symbol hacking VOPs
79 (define-vop (%set-symbol-global-value cell-set)
80 (:variant symbol-value-slot other-pointer-lowtag))
82 (define-vop (fast-symbol-global-value cell-ref)
83 (:variant symbol-value-slot other-pointer-lowtag)
84 (:policy :fast)
85 (:translate symbol-global-value))
87 (define-vop (symbol-global-value)
88 (:policy :fast-safe)
89 (:translate symbol-global-value)
90 (:args (object :scs (descriptor-reg) :to (:result 1)))
91 (:results (value :scs (descriptor-reg any-reg)))
92 (:vop-var vop)
93 (:save-p :compute-only)
94 (:generator 9
95 (let ((err-lab (generate-error-code vop 'unbound-symbol-error object)))
96 (loadw value object symbol-value-slot other-pointer-lowtag)
97 (inst cmp (reg-in-size value :dword) unbound-marker-widetag)
98 (inst jmp :e err-lab))))
100 ;; Return T if SYMBOL will be (at no later than load time) wired to a TLS index.
101 ;; When a symbol gets a tls index, it is permanently at that index, so it is
102 ;; by some definition "wired", but here the term specifically means that an
103 ;; index can/should be encoded into the instruction for reading that symbol's
104 ;; thread-local value, as contrasted with reading its index from itself.
105 ;; The BIND vop forces wiring; the BOUNDP vop never does, the SET vop doesn't
106 ;; but could, and {FAST-}SYMBOL-VALUE vops optimize their output appropriately
107 ;; based on wiring. Except when a symbol maps into a thread slot, the compiler
108 ;; doesn't care what the actual index is - that's the loader's purview.
109 (defun wired-tls-symbol-p (symbol)
110 (not (null (info :variable :wired-tls symbol))))
112 ;; Return the DISP field to use in an EA relative to thread-base-tn
113 (defun load-time-tls-offset (symbol)
114 (let ((where (info :variable :wired-tls symbol)))
115 (cond ((integerp where) where)
116 (t (make-fixup symbol :symbol-tls-index)))))
118 ;; Return T if reference to symbol doesn't need to check for no-tls-value.
119 ;; True of thread struct slots. More generally we could add a declaration.
120 (defun symbol-always-thread-local-p (symbol)
121 (let ((where (info :variable :wired-tls symbol)))
122 (or (eq where :ALWAYS-THREAD-LOCAL) (integerp where))))
124 (macrolet (;; Logic common to thread-aware SET and CAS. CELL is assigned
125 ;; to the location that should be accessed to modify SYMBOL's
126 ;; value either in the TLS or the symbol's value slot as follows:
127 ;; (1) make it look as if the TLS cell were a symbol by biasing
128 ;; upward by other-pointer-lowtag less 1 word.
129 ;; (2) conditionally make CELL point to the symbol itself
130 (compute-virtual-symbol ()
131 `(progn
132 (inst mov (reg-in-size cell :dword) (tls-index-of symbol))
133 (inst lea cell
134 (make-ea :qword :base thread-base-tn :index cell
135 :disp (- other-pointer-lowtag
136 (ash symbol-value-slot word-shift))))
137 (inst cmp (access-value-slot cell :dword) ; TLS reference
138 no-tls-value-marker-widetag)
139 (inst cmov :e cell symbol))) ; now possibly get the symbol
140 (access-wired-tls-val (sym) ; SYM is a symbol
141 `(make-ea :qword :disp (load-time-tls-offset ,sym)
142 :base thread-base-tn))
143 (access-tls-val (index size)
144 `(make-ea ,size :base thread-base-tn :index ,index :scale 1))
145 (access-value-slot (sym &optional (size :qword)) ; SYM is a TN
146 (ecase size
147 (:dword `(make-ea-for-object-slot-half
148 ,sym symbol-value-slot other-pointer-lowtag))
149 (:qword `(make-ea-for-object-slot
150 ,sym symbol-value-slot other-pointer-lowtag)))))
152 (define-vop (%compare-and-swap-symbol-value)
153 (:translate %compare-and-swap-symbol-value)
154 (:args (symbol :scs (descriptor-reg) :to (:result 0))
155 (old :scs (descriptor-reg any-reg) :target rax)
156 (new :scs (descriptor-reg any-reg)))
157 (:temporary (:sc descriptor-reg :offset rax-offset
158 :from (:argument 1) :to (:result 0)) rax)
159 #!+sb-thread
160 (:temporary (:sc descriptor-reg :to (:result 0)) cell)
161 (:results (result :scs (descriptor-reg any-reg)))
162 (:policy :fast-safe)
163 (:vop-var vop)
164 (:generator 15
165 ;; This code has two pathological cases: NO-TLS-VALUE-MARKER
166 ;; or UNBOUND-MARKER as NEW: in either case we would end up
167 ;; doing possible damage with CMPXCHG -- so don't do that!
168 ;; Even worse: don't supply old=NO-TLS-VALUE with a symbol whose
169 ;; tls-index=0, because that would succeed, assigning NEW to each
170 ;; symbol in existence having otherwise no thread-local value.
171 (let ((unbound (generate-error-code vop 'unbound-symbol-error symbol)))
172 #!+sb-thread (progn (compute-virtual-symbol)
173 (move rax old)
174 (inst cmpxchg (access-value-slot cell) new :lock))
175 #!-sb-thread (progn (move rax old)
176 ;; is the :LOCK is necessary?
177 (inst cmpxchg (access-value-slot symbol) new :lock))
178 (inst cmp (reg-in-size rax :dword) unbound-marker-widetag)
179 (inst jmp :e unbound)
180 (move result rax))))
182 #!+sb-thread
183 (progn
184 ;; TODO: SET could be shorter for any known wired-tls symbol.
185 (define-vop (set)
186 (:args (symbol :scs (descriptor-reg))
187 (value :scs (descriptor-reg any-reg)))
188 (:temporary (:sc descriptor-reg) cell)
189 (:generator 4
190 ;; Compute the address into which to store. CMOV can only move into
191 ;; a register, so we can't conditionally move into the TLS and
192 ;; conditionally move in the opposite flag sense to the symbol.
193 (compute-virtual-symbol)
194 (inst mov (access-value-slot cell) value)))
196 ;; With Symbol-Value, we check that the value isn't the trap object. So
197 ;; Symbol-Value of NIL is NIL.
198 (define-vop (symbol-value)
199 (:translate symbol-value)
200 (:policy :fast-safe)
201 (:args (symbol :scs (descriptor-reg constant) :to (:result 1)))
202 (:temporary (:sc descriptor-reg) symbol-reg)
203 (:results (value :scs (descriptor-reg any-reg)))
204 (:vop-var vop)
205 (:save-p :compute-only)
206 (:variant-vars check-boundp)
207 (:variant t)
208 (:generator 9
209 (cond
210 ((not (sc-is symbol constant)) ; SYMBOL-VALUE of a random symbol
211 ;; These reads are inextricably data-dependent
212 (inst mov (reg-in-size symbol-reg :dword) (tls-index-of symbol))
213 (inst mov value (access-tls-val symbol-reg :qword))
214 (setq symbol-reg symbol))
215 ((wired-tls-symbol-p (tn-value symbol)) ; e.g. CL:*PRINT-BASE*
216 (inst mov symbol-reg symbol) ; = MOV Rxx, [RIP-N]
217 (inst mov value (access-wired-tls-val (tn-value symbol))))
218 (t ; commonest case: constant-tn for the symbol, not wired tls
219 ;; Same data-dependencies as the non-constant-tn case.
220 (inst mov symbol-reg symbol) ; = MOV REG, [RIP-N]
221 (inst mov (reg-in-size value :dword) (tls-index-of symbol-reg))
222 (inst mov value (access-tls-val value :qword))))
223 (unless (and (sc-is symbol constant)
224 (symbol-always-thread-local-p (tn-value symbol)))
225 (inst cmp (reg-in-size value :dword) no-tls-value-marker-widetag)
226 (inst cmov :e value (access-value-slot symbol-reg)))
227 (when check-boundp
228 (inst cmp (reg-in-size value :dword) unbound-marker-widetag)
229 (inst jmp :e (generate-error-code vop 'unbound-symbol-error
230 symbol-reg)))))
232 (define-vop (fast-symbol-value symbol-value)
233 ;; KLUDGE: not really fast, in fact, because we're going to have to
234 ;; do a full lookup of the thread-local area anyway. But half of
235 ;; the meaning of FAST-SYMBOL-VALUE is "do not signal an error if
236 ;; unbound", which is used in the implementation of COPY-SYMBOL. --
237 ;; CSR, 2003-04-22
238 (:policy :fast)
239 (:variant nil)
240 (:variant-cost 5))
242 ;; SYMBOL-VALUE of a static symbol with a wired TLS index does not
243 ;; load the symbol except in the case of error, and uses no temp either.
244 ;; There's no way to express the lack of encumbrances in the general vop.
245 (define-vop (symeval/static-wired)
246 (:translate symbol-value)
247 (:policy :fast-safe)
248 ;; The predicates are orthogonal. Symbols can satisfy one, the other,
249 ;; both, or neither. This vop applies only if both.
250 (:arg-types (:constant (and (satisfies static-symbol-p)
251 (satisfies wired-tls-symbol-p))))
252 (:info symbol)
253 (:results (value :scs (descriptor-reg any-reg)))
254 (:vop-var vop)
255 (:save-p :compute-only)
256 (:variant-vars check-boundp)
257 (:variant t)
258 (:generator 5
259 (inst mov value (access-wired-tls-val symbol))
260 (unless (symbol-always-thread-local-p symbol)
261 (inst cmp (reg-in-size value :dword) no-tls-value-marker-widetag)
262 (inst cmov :e value (static-symbol-value-ea symbol)))
263 (when check-boundp
264 (let ((err-label (gen-label)))
265 (assemble (*elsewhere*)
266 (emit-label err-label)
267 (inst mov value (+ nil-value (static-symbol-offset symbol)))
268 (emit-error-break vop error-trap
269 (error-number-or-lose 'unbound-symbol-error)
270 (list value)))
271 (inst cmp (reg-in-size value :dword) unbound-marker-widetag)
272 (inst jmp :e err-label)))))
274 (define-vop (fast-symeval/static-wired symeval/static-wired)
275 (:policy :fast)
276 (:variant nil)
277 (:variant-cost 3))
279 ;; Would it be worthwhile to make a static/wired boundp vop?
280 (define-vop (boundp)
281 (:translate boundp)
282 (:policy :fast-safe)
283 (:args (object :scs (descriptor-reg)))
284 (:conditional :ne)
285 (:temporary (:sc dword-reg) temp)
286 (:generator 9
287 (inst mov temp (tls-index-of object))
288 (inst mov temp (access-tls-val temp :dword))
289 (inst cmp temp no-tls-value-marker-widetag)
290 (inst cmov :e temp (access-value-slot object :dword))
291 (inst cmp temp unbound-marker-widetag))))
293 ) ; END OF MACROLET
295 #!-sb-thread
296 (progn
297 (define-vop (symbol-value symbol-global-value)
298 (:translate symbol-value))
299 (define-vop (fast-symbol-value fast-symbol-global-value)
300 (:translate symbol-value))
301 (define-vop (set %set-symbol-global-value))
302 (define-vop (boundp)
303 (:translate boundp)
304 (:policy :fast-safe)
305 (:args (symbol :scs (descriptor-reg)))
306 (:conditional :ne)
307 (:generator 9
308 (inst cmp (make-ea-for-object-slot-half
309 symbol symbol-value-slot other-pointer-lowtag)
310 unbound-marker-widetag))))
312 (define-vop (symbol-hash)
313 (:policy :fast-safe)
314 (:translate symbol-hash)
315 (:args (symbol :scs (descriptor-reg)))
316 (:results (res :scs (any-reg)))
317 (:result-types positive-fixnum)
318 (:generator 2
319 ;; The symbol-hash slot of NIL holds NIL because it is also the
320 ;; cdr slot, so we have to zero the fixnum tag bit(s) to make sure
321 ;; it is a fixnum. The lowtag selection magic that is required to
322 ;; ensure this is explained in the comment in objdef.lisp
323 (loadw res symbol symbol-hash-slot other-pointer-lowtag)
324 (inst and res (lognot fixnum-tag-mask))))
326 ;;;; fdefinition (FDEFN) objects
328 (define-vop (fdefn-fun cell-ref) ; /pfw - alpha
329 (:variant fdefn-fun-slot other-pointer-lowtag))
331 (define-vop (safe-fdefn-fun)
332 (:translate safe-fdefn-fun)
333 (:policy :fast-safe)
334 (:args (object :scs (descriptor-reg) :to (:result 1)))
335 (:results (value :scs (descriptor-reg any-reg)))
336 (:vop-var vop)
337 (:save-p :compute-only)
338 (:generator 10
339 (loadw value object fdefn-fun-slot other-pointer-lowtag)
340 ;; byte comparison works because lowtags of function and nil differ
341 (inst cmp (reg-in-size value :byte) (logand nil-value #xff))
342 (let* ((*location-context* (make-restart-location RETRY value))
343 (err-lab (generate-error-code vop 'undefined-fun-error object)))
344 (inst jmp :e err-lab))
345 RETRY))
347 #!-immobile-code
348 (define-vop (set-fdefn-fun)
349 (:policy :fast-safe)
350 (:translate (setf fdefn-fun))
351 (:args (function :scs (descriptor-reg) :target result)
352 (fdefn :scs (descriptor-reg)))
353 (:temporary (:sc unsigned-reg) raw)
354 (:temporary (:sc unsigned-reg) type)
355 (:results (result :scs (descriptor-reg)))
356 (:generator 38
357 (load-type type function (- fun-pointer-lowtag))
358 (inst lea raw
359 (make-ea :byte :base function
360 :disp (- (* simple-fun-code-offset n-word-bytes)
361 fun-pointer-lowtag)))
362 (inst cmp (reg-in-size type :byte) simple-fun-header-widetag)
363 (inst jmp :e NORMAL-FUN)
364 (inst mov raw (make-fixup 'closure-tramp :assembly-routine))
365 NORMAL-FUN
366 (storew function fdefn fdefn-fun-slot other-pointer-lowtag)
367 (storew raw fdefn fdefn-raw-addr-slot other-pointer-lowtag)
368 (move result function)))
370 (define-vop (fdefn-makunbound)
371 (:policy :fast-safe)
372 (:translate fdefn-makunbound)
373 (:args (fdefn :scs (descriptor-reg) :target result))
374 (:results (result :scs (descriptor-reg)))
375 #!+immobile-code (:temporary (:sc unsigned-reg) temp)
376 (:generator 38
377 #!+immobile-code
378 (progn
379 (inst mov (reg-in-size temp :dword)
380 (make-fixup 'undefined-tramp :assembly-routine))
381 ;; Compute displacement from the call site
382 (inst sub (reg-in-size temp :dword) (reg-in-size fdefn :dword))
383 (inst sub (reg-in-size temp :dword)
384 (+ (- other-pointer-lowtag) (ash fdefn-raw-addr-slot word-shift) 5))
385 ;; Compute the encoding of a "CALL rel32" instruction
386 (inst shl temp 8)
387 (inst or (reg-in-size temp :byte) #xE8)
388 ;; Store
389 (storew nil-value fdefn fdefn-fun-slot other-pointer-lowtag)
390 (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))
391 #!-immobile-code
392 (progn
393 (storew nil-value fdefn fdefn-fun-slot other-pointer-lowtag)
394 (storew (make-fixup 'undefined-tramp :assembly-routine)
395 fdefn fdefn-raw-addr-slot other-pointer-lowtag))
396 (move result fdefn)))
398 ;;;; binding and unbinding
400 ;;; BIND -- Establish VAL as a binding for SYMBOL. Save the old value and
401 ;;; the symbol on the binding stack and stuff the new value into the
402 ;;; symbol.
403 ;;; See the "Chapter 9: Specials" of the SBCL Internals Manual.
405 #!+sb-thread
406 (progn
407 (define-vop (dynbind) ; bind a symbol in a PROGV form
408 (:args (val :scs (any-reg descriptor-reg))
409 (symbol :scs (descriptor-reg)))
410 (:temporary (:sc unsigned-reg :offset rax-offset) tls-index)
411 (:temporary (:sc unsigned-reg) bsp tmp)
412 (:vop-var vop)
413 (:generator 10
414 (load-binding-stack-pointer bsp)
415 (inst mov (reg-in-size tls-index :dword) (tls-index-of symbol))
416 (inst add bsp (* binding-size n-word-bytes))
417 (store-binding-stack-pointer bsp)
418 (inst test (reg-in-size tls-index :dword) (reg-in-size tls-index :dword))
419 (inst jmp :ne TLS-INDEX-VALID)
420 (inst mov tls-index symbol)
421 (invoke-asm-routine 'call 'alloc-tls-index vop tmp)
422 TLS-INDEX-VALID
423 (inst mov tmp (make-ea :qword :base thread-base-tn :index tls-index))
424 (storew tmp bsp (- binding-value-slot binding-size))
425 (storew tls-index bsp (- binding-symbol-slot binding-size))
426 (inst mov (make-ea :qword :base thread-base-tn :index tls-index) val)))
428 (define-vop (bind) ; bind a known symbol
429 (:args (val :scs (any-reg descriptor-reg)))
430 (:temporary (:sc unsigned-reg) bsp tmp)
431 (:info symbol)
432 (:generator 10
433 (inst mov bsp (* binding-size n-word-bytes))
434 (inst xadd
435 (make-ea :qword :base thread-base-tn
436 :disp (ash thread-binding-stack-pointer-slot word-shift))
437 bsp)
438 (let* ((tls-index (load-time-tls-offset symbol))
439 (tls-cell (make-ea :qword :base thread-base-tn :disp tls-index)))
440 ;; Too bad we can't use "XCHG [r12+disp], val" to write the new value
441 ;; and read the old value in one step. It will violate the constraints
442 ;; prescribed in the internal documentation on special binding.
443 (inst mov tmp tls-cell)
444 (storew tmp bsp binding-value-slot)
445 ;; Indices are small enough to be written as :DWORDs which avoids
446 ;; a REX prefix if 'bsp' happens to be any of the low 8 registers.
447 (inst mov (make-ea :dword :base bsp
448 :disp (ash binding-symbol-slot word-shift)) tls-index)
449 (inst mov tls-cell val)))))
451 #!-sb-thread
452 (define-vop (dynbind)
453 (:args (val :scs (any-reg descriptor-reg))
454 (symbol :scs (descriptor-reg)))
455 (:temporary (:sc unsigned-reg) temp bsp)
456 (:generator 5
457 (load-symbol-value bsp *binding-stack-pointer*)
458 (loadw temp symbol symbol-value-slot other-pointer-lowtag)
459 (inst add bsp (* binding-size n-word-bytes))
460 (store-symbol-value bsp *binding-stack-pointer*)
461 (storew temp bsp (- binding-value-slot binding-size))
462 (storew symbol bsp (- binding-symbol-slot binding-size))
463 (storew val symbol symbol-value-slot other-pointer-lowtag)))
465 #!+sb-thread
466 (define-vop (unbind)
467 (:temporary (:sc unsigned-reg) temp bsp tls-index)
468 (:temporary (:sc complex-double-reg) zero)
469 (:info n)
470 (:generator 0
471 (load-binding-stack-pointer bsp)
472 (inst xorpd zero zero)
473 (loop repeat n
475 (inst sub bsp (* binding-size n-word-bytes))
476 ;; Load TLS-INDEX of the SYMBOL from stack
477 (inst mov (reg-in-size tls-index :dword)
478 (make-ea :dword :base bsp :disp (* binding-symbol-slot n-word-bytes)))
480 ;; Load VALUE from stack, then restore it to the TLS area.
481 (loadw temp bsp binding-value-slot)
482 (inst mov (make-ea :qword :base thread-base-tn :index tls-index)
483 temp)
484 ;; Zero out the stack.
485 (inst movapd (make-ea :qword :base bsp) zero))
486 (store-binding-stack-pointer bsp)))
488 #!-sb-thread
489 (define-vop (unbind)
490 (:temporary (:sc unsigned-reg) symbol value bsp)
491 (:generator 0
492 (load-symbol-value bsp *binding-stack-pointer*)
493 (loadw symbol bsp (- binding-symbol-slot binding-size))
494 (loadw value bsp (- binding-value-slot binding-size))
495 (storew value symbol symbol-value-slot other-pointer-lowtag)
496 (storew 0 bsp (- binding-symbol-slot binding-size))
497 (storew 0 bsp (- binding-value-slot binding-size))
498 (inst sub bsp (* binding-size n-word-bytes))
499 (store-symbol-value bsp *binding-stack-pointer*)))
501 (define-vop (unbind-to-here)
502 (:args (where :scs (descriptor-reg any-reg)))
503 (:temporary (:sc unsigned-reg) symbol value bsp)
504 (:temporary (:sc complex-double-reg) zero)
505 (:generator 0
506 (load-binding-stack-pointer bsp)
507 (inst cmp where bsp)
508 (inst jmp :e DONE)
509 (inst xorpd zero zero)
510 LOOP
511 (inst sub bsp (* binding-size n-word-bytes))
512 ;; on sb-thread symbol is actually a tls-index, and it fits into
513 ;; 32-bits.
514 #!+sb-thread
515 (let ((tls-index (reg-in-size symbol :dword)))
516 (inst mov tls-index
517 (make-ea :dword :base bsp :disp (* binding-symbol-slot n-word-bytes)))
518 (inst test tls-index tls-index))
519 #!-sb-thread
520 (progn
521 (loadw symbol bsp binding-symbol-slot)
522 (inst test symbol symbol))
523 (inst jmp :z SKIP)
524 (loadw value bsp binding-value-slot)
525 #!-sb-thread
526 (storew value symbol symbol-value-slot other-pointer-lowtag)
527 #!+sb-thread
528 (inst mov (make-ea :qword :base thread-base-tn :index symbol)
529 value)
531 SKIP
532 (inst movapd (make-ea :qword :base bsp) zero)
534 (inst cmp where bsp)
535 (inst jmp :ne LOOP)
536 (store-binding-stack-pointer bsp)
538 DONE))
540 ;;;; closure indexing
542 (define-full-reffer closure-index-ref *
543 closure-info-offset fun-pointer-lowtag
544 (any-reg descriptor-reg) * %closure-index-ref)
546 (define-full-setter set-funcallable-instance-info *
547 funcallable-instance-info-offset fun-pointer-lowtag
548 (any-reg descriptor-reg) * %set-funcallable-instance-info)
550 (define-full-reffer funcallable-instance-info *
551 funcallable-instance-info-offset fun-pointer-lowtag
552 (descriptor-reg any-reg) * %funcallable-instance-info)
554 (define-vop (closure-ref slot-ref)
555 (:variant closure-info-offset fun-pointer-lowtag))
557 (define-vop (closure-init slot-set)
558 (:variant closure-info-offset fun-pointer-lowtag))
560 (define-vop (closure-init-from-fp)
561 (:args (object :scs (descriptor-reg)))
562 (:info offset)
563 (:generator 4
564 (storew rbp-tn object (+ closure-info-offset offset) fun-pointer-lowtag)))
566 ;;;; value cell hackery
568 (define-vop (value-cell-ref cell-ref)
569 (:variant value-cell-value-slot other-pointer-lowtag))
571 (define-vop (value-cell-set cell-set)
572 (:variant value-cell-value-slot other-pointer-lowtag))
574 ;;;; structure hackery
576 (define-vop (instance-length)
577 (:policy :fast-safe)
578 (:translate %instance-length)
579 (:args (struct :scs (descriptor-reg)))
580 (:results (res :scs (unsigned-reg)))
581 (:result-types positive-fixnum)
582 (:generator 4
583 (inst mov (reg-in-size res :word)
584 (make-ea :word :base struct
585 :disp (1+ (- instance-pointer-lowtag))))
586 (inst movzx (reg-in-size res :dword) (reg-in-size res :word))))
588 #!+compact-instance-header
589 (progn
590 (define-vop (%instance-layout)
591 (:translate %instance-layout)
592 (:policy :fast-safe)
593 (:args (object :scs (descriptor-reg)))
594 (:results (res :scs (descriptor-reg)))
595 (:variant-vars lowtag)
596 (:variant instance-pointer-lowtag)
597 (:generator 1
598 (inst mov (reg-in-size res :dword) (make-ea :dword :base object :disp (- 4 lowtag)))))
599 (define-vop (%set-instance-layout)
600 (:translate %set-instance-layout)
601 (:policy :fast-safe)
602 (:args (object :scs (descriptor-reg))
603 (value :scs (any-reg descriptor-reg) :target res))
604 (:results (res :scs (any-reg descriptor-reg)))
605 (:variant-vars lowtag)
606 (:variant instance-pointer-lowtag)
607 (:generator 2
608 (inst mov (make-ea :dword :base object :disp (- 4 lowtag)) (reg-in-size value :dword))
609 (move res value)))
610 (define-vop (%funcallable-instance-layout %instance-layout)
611 (:translate %funcallable-instance-layout)
612 (:variant fun-pointer-lowtag))
613 (define-vop (%set-funcallable-instance-layout %set-instance-layout)
614 (:translate %set-funcallable-instance-layout)
615 (:variant fun-pointer-lowtag)))
617 (define-full-reffer instance-index-ref * instance-slots-offset
618 instance-pointer-lowtag (any-reg descriptor-reg) * %instance-ref)
620 (define-full-setter instance-index-set * instance-slots-offset
621 instance-pointer-lowtag (any-reg descriptor-reg) * %instance-set)
623 (define-full-compare-and-swap %instance-cas instance
624 instance-slots-offset instance-pointer-lowtag
625 (any-reg descriptor-reg) * %instance-cas)
626 (define-full-compare-and-swap %raw-instance-cas/word instance
627 instance-slots-offset instance-pointer-lowtag
628 (unsigned-reg) unsigned-num %raw-instance-cas/word)
630 ;;;; code object frobbing
632 (define-full-reffer code-header-ref * 0 other-pointer-lowtag
633 (any-reg descriptor-reg) * code-header-ref)
635 (define-full-setter code-header-set * 0 other-pointer-lowtag
636 (any-reg descriptor-reg) * code-header-set)
638 ;;;; raw instance slot accessors
640 (flet ((make-ea-for-raw-slot (object index)
641 (etypecase index
642 (integer
643 (make-ea :qword
644 :base object
645 :disp (+ (* (+ instance-slots-offset index) n-word-bytes)
646 (- instance-pointer-lowtag))))
648 (make-ea :qword
649 :base object
650 :index index
651 :scale (ash 1 (- word-shift n-fixnum-tag-bits))
652 :disp (+ (* instance-slots-offset n-word-bytes)
653 (- instance-pointer-lowtag)))))))
654 (macrolet
655 ((def (suffix result-sc result-type inst &optional (inst/c inst))
656 `(progn
657 (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix))
658 (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix))
659 (:policy :fast-safe)
660 (:args (object :scs (descriptor-reg)) (index :scs (any-reg)))
661 (:arg-types * tagged-num)
662 (:results (value :scs (,result-sc)))
663 (:result-types ,result-type)
664 (:generator 5
665 (inst ,inst value (make-ea-for-raw-slot object index))))
666 (define-vop (,(symbolicate "RAW-INSTANCE-REF-C/" suffix))
667 (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix))
668 (:policy :fast-safe)
669 (:args (object :scs (descriptor-reg)))
670 ;; Why are we pedantic about the index constraint here
671 ;; if we're not equally so in the init vop?
672 (:arg-types * (:constant (load/store-index #.n-word-bytes
673 #.instance-pointer-lowtag
674 #.instance-slots-offset)))
675 (:info index)
676 (:results (value :scs (,result-sc)))
677 (:result-types ,result-type)
678 (:generator 4
679 (inst ,inst/c value (make-ea-for-raw-slot object index))))
680 (define-vop (,(symbolicate "RAW-INSTANCE-SET/" suffix))
681 (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix))
682 (:policy :fast-safe)
683 (:args (object :scs (descriptor-reg))
684 (index :scs (any-reg))
685 (value :scs (,result-sc) :target result))
686 (:arg-types * tagged-num ,result-type)
687 (:results (result :scs (,result-sc)))
688 (:result-types ,result-type)
689 (:generator 5
690 (inst ,inst (make-ea-for-raw-slot object index) value)
691 (move result value)))
692 (define-vop (,(symbolicate "RAW-INSTANCE-SET-C/" suffix))
693 (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix))
694 (:policy :fast-safe)
695 (:args (object :scs (descriptor-reg))
696 (value :scs (,result-sc) :target result))
697 (:arg-types * (:constant (load/store-index #.n-word-bytes
698 #.instance-pointer-lowtag
699 #.instance-slots-offset))
700 ,result-type)
701 (:info index)
702 (:results (result :scs (,result-sc)))
703 (:result-types ,result-type)
704 (:generator 4
705 (inst ,inst/c (make-ea-for-raw-slot object index) value)
706 (move result value)))
707 (define-vop (,(symbolicate "RAW-INSTANCE-INIT/" suffix))
708 (:args (object :scs (descriptor-reg))
709 (value :scs (,result-sc)))
710 (:arg-types * ,result-type)
711 (:info index)
712 (:generator 4
713 (inst ,inst/c (make-ea-for-raw-slot object index) value))))))
714 (def word unsigned-reg unsigned-num mov)
715 (def signed-word signed-reg signed-num mov)
716 (def single single-reg single-float movss)
717 (def double double-reg double-float movsd)
718 (def complex-single complex-single-reg complex-single-float movq)
719 (def complex-double complex-double-reg complex-double-float
720 movupd (if (oddp index) 'movapd 'movupd)))
722 (define-vop (raw-instance-atomic-incf/word)
723 (:translate %raw-instance-atomic-incf/word)
724 (:policy :fast-safe)
725 (:args (object :scs (descriptor-reg))
726 (index :scs (any-reg))
727 (diff :scs (unsigned-reg) :target result))
728 (:arg-types * tagged-num unsigned-num)
729 (:results (result :scs (unsigned-reg)))
730 (:result-types unsigned-num)
731 (:generator 5
732 (inst xadd (make-ea-for-raw-slot object index) diff :lock)
733 (move result diff)))
735 (define-vop (raw-instance-atomic-incf-c/word)
736 (:translate %raw-instance-atomic-incf/word)
737 (:policy :fast-safe)
738 (:args (object :scs (descriptor-reg))
739 (diff :scs (unsigned-reg) :target result))
740 (:arg-types * (:constant (load/store-index #.n-word-bytes
741 #.instance-pointer-lowtag
742 #.instance-slots-offset))
743 unsigned-num)
744 (:info index)
745 (:results (result :scs (unsigned-reg)))
746 (:result-types unsigned-num)
747 (:generator 4
748 (inst xadd (make-ea-for-raw-slot object index) diff :lock)
749 (move result diff))))