Store layout in header of funcallable-instance if #+compact-instance-header
[sbcl.git] / src / compiler / x86-64 / cell.lisp
blob21634a2aa5be2d734e4b93c7312ce30a3ed227e2
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 ((err-lab (generate-error-code vop 'undefined-fun-error object)))
343 (inst jmp :e err-lab))))
345 (define-vop (set-fdefn-fun)
346 (:policy :fast-safe)
347 (:translate (setf fdefn-fun))
348 (:args (function :scs (descriptor-reg) :target result)
349 (fdefn :scs (descriptor-reg)))
350 (:temporary (:sc unsigned-reg) raw)
351 (:temporary (:sc unsigned-reg) type)
352 (:results (result :scs (descriptor-reg)))
353 (:generator 38
354 (load-type type function (- fun-pointer-lowtag))
355 (inst lea raw
356 (make-ea :byte :base function
357 :disp (- (* simple-fun-code-offset n-word-bytes)
358 fun-pointer-lowtag)))
359 (inst cmp (reg-in-size type :byte) simple-fun-header-widetag)
360 (inst jmp :e NORMAL-FUN)
361 (inst mov raw (make-fixup 'closure-tramp :assembly-routine))
362 NORMAL-FUN
363 (storew function fdefn fdefn-fun-slot other-pointer-lowtag)
364 (storew raw fdefn fdefn-raw-addr-slot other-pointer-lowtag)
365 (move result function)))
367 (define-vop (fdefn-makunbound)
368 (:policy :fast-safe)
369 (:translate fdefn-makunbound)
370 (:args (fdefn :scs (descriptor-reg) :target result))
371 (:results (result :scs (descriptor-reg)))
372 (:generator 38
373 (storew nil-value fdefn fdefn-fun-slot other-pointer-lowtag)
374 (storew (make-fixup 'undefined-tramp :assembly-routine)
375 fdefn fdefn-raw-addr-slot other-pointer-lowtag)
376 (move result fdefn)))
378 ;;;; binding and unbinding
380 ;;; BIND -- Establish VAL as a binding for SYMBOL. Save the old value and
381 ;;; the symbol on the binding stack and stuff the new value into the
382 ;;; symbol.
383 ;;; See the "Chapter 9: Specials" of the SBCL Internals Manual.
385 #!+sb-thread
386 (progn
387 (define-vop (dynbind) ; bind a symbol in a PROGV form
388 (:args (val :scs (any-reg descriptor-reg))
389 (symbol :scs (descriptor-reg)))
390 (:temporary (:sc unsigned-reg :offset rax-offset) tls-index)
391 (:temporary (:sc unsigned-reg) bsp tmp)
392 (:vop-var vop)
393 (:generator 10
394 (load-binding-stack-pointer bsp)
395 (inst mov (reg-in-size tls-index :dword) (tls-index-of symbol))
396 (inst add bsp (* binding-size n-word-bytes))
397 (store-binding-stack-pointer bsp)
398 (inst test (reg-in-size tls-index :dword) (reg-in-size tls-index :dword))
399 (inst jmp :ne TLS-INDEX-VALID)
400 (inst mov tls-index symbol)
401 (invoke-asm-routine 'call 'alloc-tls-index vop tmp)
402 TLS-INDEX-VALID
403 (inst mov tmp (make-ea :qword :base thread-base-tn :index tls-index))
404 (storew tmp bsp (- binding-value-slot binding-size))
405 (storew tls-index bsp (- binding-symbol-slot binding-size))
406 (inst mov (make-ea :qword :base thread-base-tn :index tls-index) val)))
408 (define-vop (bind) ; bind a known symbol
409 (:args (val :scs (any-reg descriptor-reg)))
410 (:temporary (:sc unsigned-reg) bsp tmp)
411 (:info symbol)
412 (:generator 10
413 (inst mov bsp (* binding-size n-word-bytes))
414 (inst xadd
415 (make-ea :qword :base thread-base-tn
416 :disp (ash thread-binding-stack-pointer-slot word-shift))
417 bsp)
418 (let* ((tls-index (load-time-tls-offset symbol))
419 (tls-cell (make-ea :qword :base thread-base-tn :disp tls-index)))
420 ;; Too bad we can't use "XCHG [r12+disp], val" to write the new value
421 ;; and read the old value in one step. It will violate the constraints
422 ;; prescribed in the internal documentation on special binding.
423 (inst mov tmp tls-cell)
424 (storew tmp bsp binding-value-slot)
425 ;; Indices are small enough to be written as :DWORDs which avoids
426 ;; a REX prefix if 'bsp' happens to be any of the low 8 registers.
427 (inst mov (make-ea :dword :base bsp
428 :disp (ash binding-symbol-slot word-shift)) tls-index)
429 (inst mov tls-cell val)))))
431 #!-sb-thread
432 (define-vop (dynbind)
433 (:args (val :scs (any-reg descriptor-reg))
434 (symbol :scs (descriptor-reg)))
435 (:temporary (:sc unsigned-reg) temp bsp)
436 (:generator 5
437 (load-symbol-value bsp *binding-stack-pointer*)
438 (loadw temp symbol symbol-value-slot other-pointer-lowtag)
439 (inst add bsp (* binding-size n-word-bytes))
440 (store-symbol-value bsp *binding-stack-pointer*)
441 (storew temp bsp (- binding-value-slot binding-size))
442 (storew symbol bsp (- binding-symbol-slot binding-size))
443 (storew val symbol symbol-value-slot other-pointer-lowtag)))
445 #!+sb-thread
446 (define-vop (unbind)
447 (:temporary (:sc unsigned-reg) temp bsp tls-index)
448 (:temporary (:sc complex-double-reg) zero)
449 (:info n)
450 (:generator 0
451 (load-binding-stack-pointer bsp)
452 (inst xorpd zero zero)
453 (loop repeat n
455 (inst sub bsp (* binding-size n-word-bytes))
456 ;; Load TLS-INDEX of the SYMBOL from stack
457 (inst mov (reg-in-size tls-index :dword)
458 (make-ea :dword :base bsp :disp (* binding-symbol-slot n-word-bytes)))
460 ;; Load VALUE from stack, then restore it to the TLS area.
461 (loadw temp bsp binding-value-slot)
462 (inst mov (make-ea :qword :base thread-base-tn :index tls-index)
463 temp)
464 ;; Zero out the stack.
465 (inst movapd (make-ea :qword :base bsp) zero))
466 (store-binding-stack-pointer bsp)))
468 #!-sb-thread
469 (define-vop (unbind)
470 (:temporary (:sc unsigned-reg) symbol value bsp)
471 (:generator 0
472 (load-symbol-value bsp *binding-stack-pointer*)
473 (loadw symbol bsp (- binding-symbol-slot binding-size))
474 (loadw value bsp (- binding-value-slot binding-size))
475 (storew value symbol symbol-value-slot other-pointer-lowtag)
476 (storew 0 bsp (- binding-symbol-slot binding-size))
477 (storew 0 bsp (- binding-value-slot binding-size))
478 (inst sub bsp (* binding-size n-word-bytes))
479 (store-symbol-value bsp *binding-stack-pointer*)))
481 (define-vop (unbind-to-here)
482 (:args (where :scs (descriptor-reg any-reg)))
483 (:temporary (:sc unsigned-reg) symbol value bsp)
484 (:temporary (:sc complex-double-reg) zero)
485 (:generator 0
486 (load-binding-stack-pointer bsp)
487 (inst cmp where bsp)
488 (inst jmp :e DONE)
489 (inst xorpd zero zero)
490 LOOP
491 (inst sub bsp (* binding-size n-word-bytes))
492 ;; on sb-thread symbol is actually a tls-index, and it fits into
493 ;; 32-bits.
494 #!+sb-thread
495 (let ((tls-index (reg-in-size symbol :dword)))
496 (inst mov tls-index
497 (make-ea :dword :base bsp :disp (* binding-symbol-slot n-word-bytes)))
498 (inst test tls-index tls-index))
499 #!-sb-thread
500 (progn
501 (loadw symbol bsp binding-symbol-slot)
502 (inst test symbol symbol))
503 (inst jmp :z SKIP)
504 (loadw value bsp binding-value-slot)
505 #!-sb-thread
506 (storew value symbol symbol-value-slot other-pointer-lowtag)
507 #!+sb-thread
508 (inst mov (make-ea :qword :base thread-base-tn :index symbol)
509 value)
511 SKIP
512 (inst movapd (make-ea :qword :base bsp) zero)
514 (inst cmp where bsp)
515 (inst jmp :ne LOOP)
516 (store-binding-stack-pointer bsp)
518 DONE))
520 ;;;; closure indexing
522 (define-full-reffer closure-index-ref *
523 closure-info-offset fun-pointer-lowtag
524 (any-reg descriptor-reg) * %closure-index-ref)
526 (define-full-setter set-funcallable-instance-info *
527 funcallable-instance-info-offset fun-pointer-lowtag
528 (any-reg descriptor-reg) * %set-funcallable-instance-info)
530 (define-full-reffer funcallable-instance-info *
531 funcallable-instance-info-offset fun-pointer-lowtag
532 (descriptor-reg any-reg) * %funcallable-instance-info)
534 (define-vop (closure-ref slot-ref)
535 (:variant closure-info-offset fun-pointer-lowtag))
537 (define-vop (closure-init slot-set)
538 (:variant closure-info-offset fun-pointer-lowtag))
540 (define-vop (closure-init-from-fp)
541 (:args (object :scs (descriptor-reg)))
542 (:info offset)
543 (:generator 4
544 (storew rbp-tn object (+ closure-info-offset offset) fun-pointer-lowtag)))
546 ;;;; value cell hackery
548 (define-vop (value-cell-ref cell-ref)
549 (:variant value-cell-value-slot other-pointer-lowtag))
551 (define-vop (value-cell-set cell-set)
552 (:variant value-cell-value-slot other-pointer-lowtag))
554 ;;;; structure hackery
556 (define-vop (instance-length)
557 (:policy :fast-safe)
558 (:translate %instance-length)
559 (:args (struct :scs (descriptor-reg)))
560 (:results (res :scs (unsigned-reg)))
561 (:result-types positive-fixnum)
562 (:generator 4
563 (inst mov (reg-in-size res :word)
564 (make-ea :word :base struct
565 :disp (1+ (- instance-pointer-lowtag))))
566 (inst movzx (reg-in-size res :dword) (reg-in-size res :word))))
568 #!+compact-instance-header
569 (progn
570 (define-vop (%instance-layout)
571 (:translate %instance-layout)
572 (:policy :fast-safe)
573 (:args (object :scs (descriptor-reg)))
574 (:results (res :scs (any-reg descriptor-reg)))
575 (:variant-vars lowtag)
576 (:variant instance-pointer-lowtag)
577 (:generator 1
578 (inst mov (reg-in-size res :dword) (make-ea :dword :base object :disp (- 4 lowtag)))))
579 (define-vop (%set-instance-layout)
580 (:translate %set-instance-layout)
581 (:policy :fast-safe)
582 (:args (object :scs (descriptor-reg))
583 (value :scs (any-reg descriptor-reg) :target res))
584 (:results (res :scs (any-reg descriptor-reg)))
585 (:variant-vars lowtag)
586 (:variant instance-pointer-lowtag)
587 (:generator 2
588 (inst mov (make-ea :dword :base object :disp (- 4 lowtag)) (reg-in-size value :dword))
589 (move res value)))
590 (define-vop (%funcallable-instance-layout %instance-layout)
591 (:translate %funcallable-instance-layout)
592 (:variant fun-pointer-lowtag))
593 (define-vop (%set-funcallable-instance-layout %set-instance-layout)
594 (:translate %set-funcallable-instance-layout)
595 (:variant fun-pointer-lowtag)))
597 (define-full-reffer instance-index-ref * instance-slots-offset
598 instance-pointer-lowtag (any-reg descriptor-reg) * %instance-ref)
600 (define-full-setter instance-index-set * instance-slots-offset
601 instance-pointer-lowtag (any-reg descriptor-reg) * %instance-set)
603 (define-full-compare-and-swap %instance-cas instance
604 instance-slots-offset instance-pointer-lowtag
605 (any-reg descriptor-reg) * %instance-cas)
606 (define-full-compare-and-swap %raw-instance-cas/word instance
607 instance-slots-offset instance-pointer-lowtag
608 (unsigned-reg) unsigned-num %raw-instance-cas/word)
610 ;;;; code object frobbing
612 (define-full-reffer code-header-ref * 0 other-pointer-lowtag
613 (any-reg descriptor-reg) * code-header-ref)
615 (define-full-setter code-header-set * 0 other-pointer-lowtag
616 (any-reg descriptor-reg) * code-header-set)
618 ;;;; raw instance slot accessors
620 (flet ((make-ea-for-raw-slot (object index)
621 (etypecase index
622 (integer
623 (make-ea :qword
624 :base object
625 :disp (+ (* (+ instance-slots-offset index) n-word-bytes)
626 (- instance-pointer-lowtag))))
628 (make-ea :qword
629 :base object
630 :index index
631 :scale (ash 1 (- word-shift n-fixnum-tag-bits))
632 :disp (+ (* instance-slots-offset n-word-bytes)
633 (- instance-pointer-lowtag)))))))
634 (macrolet
635 ((def (suffix result-sc result-type inst &optional (inst/c inst))
636 `(progn
637 (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix))
638 (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix))
639 (:policy :fast-safe)
640 (:args (object :scs (descriptor-reg)) (index :scs (any-reg)))
641 (:arg-types * tagged-num)
642 (:results (value :scs (,result-sc)))
643 (:result-types ,result-type)
644 (:generator 5
645 (inst ,inst value (make-ea-for-raw-slot object index))))
646 (define-vop (,(symbolicate "RAW-INSTANCE-REF-C/" suffix))
647 (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix))
648 (:policy :fast-safe)
649 (:args (object :scs (descriptor-reg)))
650 ;; Why are we pedantic about the index constraint here
651 ;; if we're not equally so in the init vop?
652 (:arg-types * (:constant (load/store-index #.n-word-bytes
653 #.instance-pointer-lowtag
654 #.instance-slots-offset)))
655 (:info index)
656 (:results (value :scs (,result-sc)))
657 (:result-types ,result-type)
658 (:generator 4
659 (inst ,inst/c value (make-ea-for-raw-slot object index))))
660 (define-vop (,(symbolicate "RAW-INSTANCE-SET/" suffix))
661 (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix))
662 (:policy :fast-safe)
663 (:args (object :scs (descriptor-reg))
664 (index :scs (any-reg))
665 (value :scs (,result-sc) :target result))
666 (:arg-types * tagged-num ,result-type)
667 (:results (result :scs (,result-sc)))
668 (:result-types ,result-type)
669 (:generator 5
670 (inst ,inst (make-ea-for-raw-slot object index) value)
671 (move result value)))
672 (define-vop (,(symbolicate "RAW-INSTANCE-SET-C/" suffix))
673 (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix))
674 (:policy :fast-safe)
675 (:args (object :scs (descriptor-reg))
676 (value :scs (,result-sc) :target result))
677 (:arg-types * (:constant (load/store-index #.n-word-bytes
678 #.instance-pointer-lowtag
679 #.instance-slots-offset))
680 ,result-type)
681 (:info index)
682 (:results (result :scs (,result-sc)))
683 (:result-types ,result-type)
684 (:generator 4
685 (inst ,inst/c (make-ea-for-raw-slot object index) value)
686 (move result value)))
687 (define-vop (,(symbolicate "RAW-INSTANCE-INIT/" suffix))
688 (:args (object :scs (descriptor-reg))
689 (value :scs (,result-sc)))
690 (:arg-types * ,result-type)
691 (:info index)
692 (:generator 4
693 (inst ,inst/c (make-ea-for-raw-slot object index) value))))))
694 (def word unsigned-reg unsigned-num mov)
695 (def signed-word signed-reg signed-num mov)
696 (def single single-reg single-float movss)
697 (def double double-reg double-float movsd)
698 (def complex-single complex-single-reg complex-single-float movq)
699 (def complex-double complex-double-reg complex-double-float
700 movupd (if (oddp index) 'movapd 'movupd)))
702 (define-vop (raw-instance-atomic-incf/word)
703 (:translate %raw-instance-atomic-incf/word)
704 (:policy :fast-safe)
705 (:args (object :scs (descriptor-reg))
706 (index :scs (any-reg))
707 (diff :scs (unsigned-reg) :target result))
708 (:arg-types * tagged-num unsigned-num)
709 (:results (result :scs (unsigned-reg)))
710 (:result-types unsigned-num)
711 (:generator 5
712 (inst xadd (make-ea-for-raw-slot object index) diff :lock)
713 (move result diff)))
715 (define-vop (raw-instance-atomic-incf-c/word)
716 (:translate %raw-instance-atomic-incf/word)
717 (:policy :fast-safe)
718 (:args (object :scs (descriptor-reg))
719 (diff :scs (unsigned-reg) :target result))
720 (:arg-types * (:constant (load/store-index #.n-word-bytes
721 #.instance-pointer-lowtag
722 #.instance-slots-offset))
723 unsigned-num)
724 (:info index)
725 (:results (result :scs (unsigned-reg)))
726 (:result-types unsigned-num)
727 (:generator 4
728 (inst xadd (make-ea-for-raw-slot object index) diff :lock)
729 (move result diff))))