1 ;;;; various primitive memory access VOPs for the x86 VM
3 ;;;; This software is part of the SBCL system. See the README file for
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.
14 ;;;; data object ref/set stuff
17 (:args
(object :scs
(descriptor-reg)))
18 (:info name offset lowtag
)
20 (:results
(result :scs
(descriptor-reg any-reg
)))
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
)
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
39 :disp
(- (* offset n-word-bytes
)
41 (encode-value-if-immediate value
)
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
)
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.
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
)
67 (:info name offset lowtag
)
69 (:results
(result :scs
(descriptor-reg any-reg
)))
72 (inst cmpxchg
(make-ea :qword
:base object
73 :disp
(- (* offset n-word-bytes
) lowtag
))
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
)
85 (:translate symbol-global-value
))
87 (define-vop (symbol-global-value)
89 (:translate symbol-global-value
)
90 (:args
(object :scs
(descriptor-reg) :to
(:result
1)))
91 (:results
(value :scs
(descriptor-reg any-reg
)))
93 (:save-p
:compute-only
)
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 ()
132 (inst mov
(reg-in-size cell
:dword
) (tls-index-of symbol
))
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
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
)
160 (:temporary
(:sc descriptor-reg
:to
(:result
0)) cell
)
161 (:results
(result :scs
(descriptor-reg any-reg
)))
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)
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
)
184 ;; TODO: SET could be shorter for any known wired-tls symbol.
186 (:args
(symbol :scs
(descriptor-reg))
187 (value :scs
(descriptor-reg any-reg
)))
188 (:temporary
(:sc descriptor-reg
) cell
)
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
)
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
)))
205 (:save-p
:compute-only
)
206 (:variant-vars check-boundp
)
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
)))
228 (inst cmp
(reg-in-size value
:dword
) unbound-marker-widetag
)
229 (inst jmp
:e
(generate-error-code vop
'unbound-symbol-error
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. --
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
)
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
))))
253 (:results
(value :scs
(descriptor-reg any-reg
)))
255 (:save-p
:compute-only
)
256 (:variant-vars check-boundp
)
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
)))
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
)
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
)
279 ;; Would it be worthwhile to make a static/wired boundp vop?
283 (:args
(object :scs
(descriptor-reg)))
285 (:temporary
(:sc dword-reg
) temp
)
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
))))
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
))
305 (:args
(symbol :scs
(descriptor-reg)))
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)
314 (:translate symbol-hash
)
315 (:args
(symbol :scs
(descriptor-reg)))
316 (:results
(res :scs
(any-reg)))
317 (:result-types positive-fixnum
)
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
)
334 (:args
(object :scs
(descriptor-reg) :to
(:result
1)))
335 (:results
(value :scs
(descriptor-reg any-reg
)))
337 (:save-p
:compute-only
)
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)
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)))
354 (load-type type function
(- fun-pointer-lowtag
))
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
))
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)
369 (:translate fdefn-makunbound
)
370 (:args
(fdefn :scs
(descriptor-reg) :target result
))
371 (:results
(result :scs
(descriptor-reg)))
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
383 ;;; See the "Chapter 9: Specials" of the SBCL Internals Manual.
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
)
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
)
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
)
413 (inst mov bsp
(* binding-size n-word-bytes
))
415 (make-ea :qword
:base thread-base-tn
416 :disp
(ash thread-binding-stack-pointer-slot word-shift
))
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
)))))
432 (define-vop (dynbind)
433 (:args
(val :scs
(any-reg descriptor-reg
))
434 (symbol :scs
(descriptor-reg)))
435 (:temporary
(:sc unsigned-reg
) temp bsp
)
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
)))
447 (:temporary
(:sc unsigned-reg
) temp bsp tls-index
)
448 (:temporary
(:sc complex-double-reg
) zero
)
451 (load-binding-stack-pointer bsp
)
452 (inst xorpd zero zero
)
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
)
464 ;; Zero out the stack.
465 (inst movapd
(make-ea :qword
:base bsp
) zero
))
466 (store-binding-stack-pointer bsp
)))
470 (:temporary
(:sc unsigned-reg
) symbol value bsp
)
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
)
486 (load-binding-stack-pointer bsp
)
489 (inst xorpd zero zero
)
491 (inst sub bsp
(* binding-size n-word-bytes
))
492 ;; on sb-thread symbol is actually a tls-index, and it fits into
495 (let ((tls-index (reg-in-size symbol
:dword
)))
497 (make-ea :dword
:base bsp
:disp
(* binding-symbol-slot n-word-bytes
)))
498 (inst test tls-index tls-index
))
501 (loadw symbol bsp binding-symbol-slot
)
502 (inst test symbol symbol
))
504 (loadw value bsp binding-value-slot
)
506 (storew value symbol symbol-value-slot other-pointer-lowtag
)
508 (inst mov
(make-ea :qword
:base thread-base-tn
:index symbol
)
512 (inst movapd
(make-ea :qword
:base bsp
) zero
)
516 (store-binding-stack-pointer bsp
)
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)))
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)
558 (:translate %instance-length
)
559 (:args
(struct :scs
(descriptor-reg)))
560 (:results
(res :scs
(unsigned-reg)))
561 (:result-types positive-fixnum
)
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
570 (define-vop (%instance-layout
)
571 (:translate %instance-layout
)
573 (:args
(object :scs
(descriptor-reg)))
574 (:results
(res :scs
(any-reg descriptor-reg
)))
575 (:variant-vars lowtag
)
576 (:variant instance-pointer-lowtag
)
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
)
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
)
588 (inst mov
(make-ea :dword
:base object
:disp
(- 4 lowtag
)) (reg-in-size value
:dword
))
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
)
625 :disp
(+ (* (+ instance-slots-offset index
) n-word-bytes
)
626 (- instance-pointer-lowtag
))))
631 :scale
(ash 1 (- word-shift n-fixnum-tag-bits
))
632 :disp
(+ (* instance-slots-offset n-word-bytes
)
633 (- instance-pointer-lowtag
)))))))
635 ((def (suffix result-sc result-type inst
&optional
(inst/c inst
))
637 (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix
))
638 (:translate
,(symbolicate "%RAW-INSTANCE-REF/" suffix
))
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
)
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
))
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
)))
656 (:results
(value :scs
(,result-sc
)))
657 (:result-types
,result-type
)
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
))
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
)
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
))
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
))
682 (:results
(result :scs
(,result-sc
)))
683 (:result-types
,result-type
)
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
)
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
)
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
)
712 (inst xadd
(make-ea-for-raw-slot object index
) diff
:lock
)
715 (define-vop (raw-instance-atomic-incf-c/word
)
716 (:translate %raw-instance-atomic-incf
/word
)
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
))
725 (:results
(result :scs
(unsigned-reg)))
726 (:result-types unsigned-num
)
728 (inst xadd
(make-ea-for-raw-slot object index
) diff
:lock
)
729 (move result diff
))))