;;;; files for more information.
(in-package "SB!VM")
-
-(file-comment
- "$Header$")
\f
;;;; type frobbing VOPs
-(define-vop (get-lowtag)
- (:translate get-lowtag)
+(define-vop (lowtag-of)
+ (:translate lowtag-of)
(:policy :fast-safe)
(:args (object :scs (any-reg descriptor-reg control-stack)
- :target result))
+ :target result))
(:results (result :scs (unsigned-reg)))
(:result-types positive-fixnum)
(:generator 1
(move result object)
(inst and result lowtag-mask)))
-(define-vop (get-type)
- (:translate get-type)
+(define-vop (widetag-of)
+ (:translate widetag-of)
(:policy :fast-safe)
(:args (object :scs (descriptor-reg)))
(:temporary (:sc unsigned-reg :offset eax-offset :to (:result 0)) eax)
(:generator 6
(inst mov eax object)
(inst and al-tn lowtag-mask)
- (inst cmp al-tn other-pointer-type)
+ (inst cmp al-tn other-pointer-lowtag)
(inst jmp :e other-ptr)
- (inst cmp al-tn function-pointer-type)
+ (inst cmp al-tn fun-pointer-lowtag)
(inst jmp :e function-ptr)
- ;; pick off structures and list pointers
+ ;; Pick off structures and list pointers.
(inst test al-tn 1)
(inst jmp :ne done)
- ;; pick off fixnums
- (inst and al-tn 3)
+ ;; Pick off fixnums.
+ (inst and al-tn fixnum-tag-mask)
(inst jmp :e done)
;; must be an other immediate
(inst jmp done)
FUNCTION-PTR
- (load-type al-tn object (- sb!vm:function-pointer-type))
+ (load-type al-tn object (- fun-pointer-lowtag))
(inst jmp done)
OTHER-PTR
- (load-type al-tn object (- sb!vm:other-pointer-type))
+ (load-type al-tn object (- other-pointer-lowtag))
DONE
(inst movzx result al-tn)))
\f
-(define-vop (function-subtype)
- (:translate function-subtype)
+(define-vop (fun-subtype)
+ (:translate fun-subtype)
(:policy :fast-safe)
(:args (function :scs (descriptor-reg)))
(:temporary (:sc byte-reg :from (:eval 0) :to (:eval 1)) temp)
(:results (result :scs (unsigned-reg)))
(:result-types positive-fixnum)
(:generator 6
- (load-type temp function (- sb!vm:function-pointer-type))
+ (load-type temp function (- fun-pointer-lowtag))
(inst movzx result temp)))
-(define-vop (set-function-subtype)
- (:translate (setf function-subtype))
+(define-vop (set-fun-subtype)
+ (:translate (setf fun-subtype))
(:policy :fast-safe)
(:args (type :scs (unsigned-reg) :target eax)
- (function :scs (descriptor-reg)))
+ (function :scs (descriptor-reg)))
(:arg-types positive-fixnum *)
(:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
- :to (:result 0) :target result)
- eax)
+ :to (:result 0) :target result)
+ eax)
(:results (result :scs (unsigned-reg)))
(:result-types positive-fixnum)
(:generator 6
(move eax type)
- (inst mov
- (make-ea :byte :base function :disp (- function-pointer-type))
- al-tn)
+ (storeb al-tn function 0 fun-pointer-lowtag)
(move result eax)))
(define-vop (get-header-data)
(:results (res :scs (unsigned-reg)))
(:result-types positive-fixnum)
(:generator 6
- (loadw res x 0 other-pointer-type)
- (inst shr res type-bits)))
+ (loadw res x 0 other-pointer-lowtag)
+ (inst shr res n-widetag-bits)))
(define-vop (get-closure-length)
(:translate get-closure-length)
(:results (res :scs (unsigned-reg)))
(:result-types positive-fixnum)
(:generator 6
- (loadw res x 0 function-pointer-type)
- (inst shr res type-bits)))
+ (loadw res x 0 fun-pointer-lowtag)
+ (inst shr res n-widetag-bits)))
(define-vop (set-header-data)
(:translate set-header-data)
(:policy :fast-safe)
(:args (x :scs (descriptor-reg) :target res :to (:result 0))
- (data :scs (any-reg) :target eax))
+ (data :scs (any-reg) :target eax))
(:arg-types * positive-fixnum)
(:results (res :scs (descriptor-reg)))
(:temporary (:sc unsigned-reg :offset eax-offset
- :from (:argument 1) :to (:result 0)) eax)
+ :from (:argument 1) :to (:result 0)) eax)
(:generator 6
(move eax data)
- (inst shl eax (- type-bits 2))
- (inst mov al-tn (make-ea :byte :base x :disp (- other-pointer-type)))
- (storew eax x 0 other-pointer-type)
+ (inst shl eax (- n-widetag-bits 2))
+ (inst mov al-tn (make-ea :byte :base x :disp (- other-pointer-lowtag)))
+ (storew eax x 0 other-pointer-lowtag)
(move res x)))
\f
-(define-vop (make-fixnum)
+(define-vop (pointer-hash)
+ (:translate pointer-hash)
(:args (ptr :scs (any-reg descriptor-reg) :target res))
(:results (res :scs (any-reg descriptor-reg)))
+ (:policy :fast-safe)
(:generator 1
- ;; Some code (the hash table code) depends on this returning a
- ;; positive number so make sure it does.
(move res ptr)
- (inst shl res 3)
+ ;; Mask the lowtag, and shift the whole address into a positive
+ ;; fixnum.
+ (inst and res (lognot lowtag-mask))
(inst shr res 1)))
(define-vop (make-other-immediate-type)
(:args (val :scs (any-reg descriptor-reg) :target res)
- (type :scs (unsigned-reg immediate)))
+ (type :scs (unsigned-reg immediate)))
(:results (res :scs (any-reg descriptor-reg) :from (:argument 0)))
(:generator 2
(move res val)
- (inst shl res (- type-bits 2))
+ (inst shl res (- n-widetag-bits n-fixnum-tag-bits))
(inst or res (sc-case type
- (unsigned-reg type)
- (immediate (tn-value type))))))
+ (unsigned-reg type)
+ (immediate (tn-value type))))))
\f
;;;; allocation
(:translate binding-stack-pointer-sap)
(:policy :fast-safe)
(:generator 1
- (load-symbol-value int *binding-stack-pointer*)))
+ (load-binding-stack-pointer int)))
(defknown (setf binding-stack-pointer-sap)
(system-area-pointer) system-area-pointer ())
(:translate (setf binding-stack-pointer-sap))
(:policy :fast-safe)
(:generator 1
- (store-symbol-value new-value *binding-stack-pointer*)
+ (store-binding-stack-pointer new-value)
(move int new-value)))
(define-vop (control-stack-pointer-sap)
(:results (sap :scs (sap-reg) :from (:argument 0)))
(:result-types system-area-pointer)
(:generator 10
- (loadw sap code 0 other-pointer-type)
- (inst shr sap type-bits)
+ (loadw sap code 0 other-pointer-lowtag)
+ (inst shr sap n-widetag-bits)
(inst lea sap (make-ea :byte :base code :index sap :scale 4
- :disp (- other-pointer-type)))))
+ :disp (- other-pointer-lowtag)))))
-(define-vop (compute-function)
+(define-vop (compute-fun)
(:args (code :scs (descriptor-reg) :to (:result 0))
- (offset :scs (signed-reg unsigned-reg) :to (:result 0)))
+ (offset :scs (signed-reg unsigned-reg) :to (:result 0)))
(:arg-types * positive-fixnum)
(:results (func :scs (descriptor-reg) :from (:argument 0)))
(:generator 10
- (loadw func code 0 other-pointer-type)
- (inst shr func type-bits)
+ (loadw func code 0 other-pointer-lowtag)
+ (inst shr func n-widetag-bits)
(inst lea func
- (make-ea :byte :base offset :index func :scale 4
- :disp (- function-pointer-type other-pointer-type)))
+ (make-ea :byte :base offset :index func :scale 4
+ :disp (- fun-pointer-lowtag other-pointer-lowtag)))
(inst add func code)))
-(defknown %function-self (function) function (flushable))
-
-(define-vop (%function-self)
+(define-vop (%simple-fun-self)
(:policy :fast-safe)
- (:translate %function-self)
+ (:translate %simple-fun-self)
(:args (function :scs (descriptor-reg)))
(:results (result :scs (descriptor-reg)))
(:generator 3
- (loadw result function function-self-slot function-pointer-type)
+ (loadw result function simple-fun-self-slot fun-pointer-lowtag)
(inst lea result
- (make-ea :byte :base result
- :disp (- function-pointer-type
- (* function-code-offset word-bytes))))))
+ (make-ea :byte :base result
+ :disp (- fun-pointer-lowtag
+ (* simple-fun-code-offset n-word-bytes))))))
-;;; The closure function slot is a pointer to raw code on X86 instead of
-;;; a pointer to the code function object itself. This VOP is used
+;;; The closure function slot is a pointer to raw code on X86 instead
+;;; of a pointer to the code function object itself. This VOP is used
;;; to reference the function object given the closure object.
-(def-source-transform %closure-function (closure)
- `(%function-self ,closure))
+(define-source-transform %closure-fun (closure)
+ `(%simple-fun-self ,closure))
-(def-source-transform %funcallable-instance-function (fin)
- `(%function-self ,fin))
-
-(defknown (setf %function-self) (function function) function (unsafe))
-
-(define-vop (%set-function-self)
+(define-vop (%set-fun-self)
(:policy :fast-safe)
- (:translate (setf %function-self))
+ (:translate (setf %simple-fun-self))
(:args (new-self :scs (descriptor-reg) :target result :to :result)
- (function :scs (descriptor-reg) :to :result))
+ (function :scs (descriptor-reg) :to :result))
(:temporary (:sc any-reg :from (:argument 0) :to :result) temp)
(:results (result :scs (descriptor-reg)))
(:generator 3
- (inst lea temp
- (make-ea :byte :base new-self
- :disp (- (ash function-code-offset word-shift)
- function-pointer-type)))
- (storew temp function function-self-slot function-pointer-type)
+ (inst lea temp (make-ea-for-object-slot new-self simple-fun-code-offset
+ fun-pointer-lowtag))
+ (storew temp function simple-fun-self-slot fun-pointer-lowtag)
(move result new-self)))
-
-;; We would have really liked to use a source-transform for this, but
-;; they don't work with SETF functions.
-(defknown ((setf %funcallable-instance-function)) (function function) function
- (unsafe))
-(deftransform (setf %funcallable-instance-function) ((value fin))
- '(setf (%function-self fin) value))
\f
;;;; other miscellaneous VOPs
-(defknown sb!unix::do-pending-interrupt () (values))
-(define-vop (sb!unix::do-pending-interrupt)
+(defknown sb!unix::receive-pending-interrupt () (values))
+(define-vop (sb!unix::receive-pending-interrupt)
(:policy :fast-safe)
- (:translate sb!unix::do-pending-interrupt)
+ (:translate sb!unix::receive-pending-interrupt)
(:generator 1
(inst break pending-interrupt-trap)))
+#!+sb-thread
+(defknown current-thread-offset-sap ((unsigned-byte 32))
+ system-area-pointer (flushable))
+
+#!+sb-thread
+(define-vop (current-thread-offset-sap)
+ (:results (sap :scs (sap-reg)))
+ (:result-types system-area-pointer)
+ (:translate current-thread-offset-sap)
+ (:args (n :scs (unsigned-reg) :target sap))
+ (:arg-types unsigned-num)
+ (:policy :fast-safe)
+ (:generator 2
+ (inst mov sap (make-ea :dword :disp 0 :index n :scale 4) :fs)))
+
(define-vop (halt)
(:generator 1
(inst break halt-trap)))
(note-next-instruction vop :internal-error)
(inst wait)))
\f
-;;;; dynamic vop count collection support
+;;;; Miscellany
+
+;;; the RDTSC instruction (present on Pentium processors and
+;;; successors) allows you to access the time-stamp counter, a 64-bit
+;;; model-specific register that counts executed cycles. The
+;;; instruction returns the low cycle count in EAX and high cycle
+;;; count in EDX.
+;;;
+;;; In order to obtain more significant results on out-of-order
+;;; processors (such as the Pentium II and later), we issue a
+;;; serializing CPUID instruction before reading the cycle counter.
+;;; This instruction is used for its side effect of emptying the
+;;; processor pipeline, to ensure that the RDTSC instruction is
+;;; executed once all pending instructions have been completed.
+;;; CPUID writes to EBX and ECX in addition to EAX and EDX, so
+;;; they need to be added as temporaries.
+;;;
+;;; Note that cache effects mean that the cycle count can vary for
+;;; different executions of the same code (it counts cycles, not
+;;; retired instructions). Furthermore, the results are per-processor
+;;; and not per-process, so are unreliable on multiprocessor machines
+;;; where processes can migrate between processors.
+;;;
+;;; This method of obtaining a cycle count has the advantage of being
+;;; very fast (around 20 cycles), and of not requiring a system call.
+;;; However, you need to know your processor's clock speed to translate
+;;; this into real execution time.
+;;;
+;;; FIXME: This about the WITH-CYCLE-COUNTER interface a bit, and then
+;;; perhaps export it from SB-SYS.
+
+(defknown %read-cycle-counter () (values (unsigned-byte 32) (unsigned-byte 32)) ())
+
+(define-vop (%read-cycle-counter)
+ (:policy :fast-safe)
+ (:translate %read-cycle-counter)
+ (:temporary (:sc unsigned-reg :offset eax-offset :target lo) eax)
+ (:temporary (:sc unsigned-reg :offset edx-offset :target hi) edx)
+ (:temporary (:sc unsigned-reg :offset ebx-offset) ebx)
+ (:temporary (:sc unsigned-reg :offset ecx-offset) ecx)
+ (:ignore ebx ecx)
+ (:results (hi :scs (unsigned-reg))
+ (lo :scs (unsigned-reg)))
+ (:result-types unsigned-num unsigned-num)
+ (:generator 5
+ (inst xor eax eax)
+ ;; Intel docs seem quite consistent on only using CPUID before RDTSC,
+ ;; not both before and after. Go figure.
+ (inst cpuid)
+ (inst rdtsc)
+ (move lo eax)
+ (move hi edx)))
+
+(defmacro with-cycle-counter (&body body)
+ "Returns the primary value of BODY as the primary value, and the
+number of CPU cycles elapsed as secondary value. EXPERIMENTAL."
+ (with-unique-names (hi0 hi1 lo0 lo1)
+ `(multiple-value-bind (,hi0 ,lo0) (%read-cycle-counter)
+ (values (locally ,@body)
+ (multiple-value-bind (,hi1 ,lo1) (%read-cycle-counter)
+ (+ (ash (- ,hi1 ,hi0) 32)
+ (- ,lo1 ,lo0)))))))
#!+sb-dyncount
(define-vop (count-me)
(:args (count-vector :scs (descriptor-reg)))
(:info index)
(:generator 0
- (inst inc (make-ea :dword :base count-vector
- :disp (- (* (+ vector-data-offset index) word-bytes)
- other-pointer-type)))))
+ (inst inc (make-ea-for-vector-data count-vector :offset index))))
\f
-;;;; primitive multi-thread support
+;;;; Memory barrier support
+
+#!+memory-barrier-vops
+(define-vop (%compiler-barrier)
+ (:policy :fast-safe)
+ (:translate %compiler-barrier)
+ (:generator 3))
+
+#!+memory-barrier-vops
+(define-vop (%memory-barrier)
+ (:policy :fast-safe)
+ (:translate %memory-barrier)
+ (:generator 3
+ (inst add (make-ea :dword :base esp-tn) 0 :lock)))
-(defknown control-stack-fork ((simple-array (unsigned-byte 32) (*)) t)
- (member t nil))
+#!+memory-barrier-vops
+(define-vop (%read-barrier)
+ (:policy :fast-safe)
+ (:translate %read-barrier)
+ (:generator 3))
-(define-vop (control-stack-fork)
+#!+memory-barrier-vops
+(define-vop (%write-barrier)
(:policy :fast-safe)
- (:translate control-stack-fork)
- (:args (save-stack :scs (descriptor-reg) :to :result)
- (inherit :scs (descriptor-reg)))
- (:arg-types simple-array-unsigned-byte-32 *)
- (:results (child :scs (descriptor-reg)))
- (:result-types t)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
- (:save-p t)
- (:generator 25
- (inst cmp inherit *nil-value*)
- (inst jmp :e FRESH-STACK)
-
- ;; Child inherits the stack of the parent.
-
- ;; Setup the return context.
- (inst push (make-fixup nil :code-object return))
- (inst push ebp-tn)
- ;; Save the stack.
- (inst xor index index)
- ;; First the stack-pointer.
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- esp-tn)
- (inst inc index)
- (inst mov stack (make-fixup (extern-alien-name "control_stack_end")
- :foreign))
- (inst jmp-short LOOP)
-
- FRESH-STACK
- ;; Child has a fresh control stack.
-
- ;; Set up the return context.
- (inst push (make-fixup nil :code-object return))
- (inst mov stack (make-fixup (extern-alien-name "control_stack_end")
- :foreign))
- ;; The new FP is the top of the stack.
- (inst push stack)
- ;; Save the stack.
- (inst xor index index)
- ;; First save the adjusted stack-pointer.
- (inst sub stack ebp-tn)
- (inst add stack esp-tn)
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- stack)
- ;; Save the current frame, replacing the OCFP and RA by 0.
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* (+ sb!vm:vector-data-offset 1)
- sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- 0)
- ;; Save 0 for the OCFP.
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* (+ sb!vm:vector-data-offset 2)
- sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- 0)
- (inst add index 3)
- ;; Copy the remainder of the frame, skiping the OCFP and RA which
- ;; are saved above.
- (inst lea stack (make-ea :byte :base ebp-tn :disp -8))
-
- LOOP
- (inst cmp stack esp-tn)
- (inst jmp :le stack-save-done)
- (inst sub stack 4)
- (inst mov temp (make-ea :dword :base stack))
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- temp)
- (inst inc index)
- (inst jmp-short LOOP)
-
- RETURN
- ;; Stack already clean if it reaches here. Parent returns NIL.
- (inst mov child *nil-value*)
- (inst jmp-short DONE)
-
- STACK-SAVE-DONE
- ;; Cleanup the stack
- (inst add esp-tn 8)
- ;; Child returns T.
- (load-symbol child t)
- DONE))
-
-(defknown control-stack-resume ((simple-array (unsigned-byte 32) (*))
- (simple-array (unsigned-byte 32) (*)))
- (values))
-
-(define-vop (control-stack-resume)
+ (:translate %write-barrier)
+ (:generator 3))
+
+#!+memory-barrier-vops
+(define-vop (%data-dependency-barrier)
(:policy :fast-safe)
- (:translate control-stack-resume)
- (:args (save-stack :scs (descriptor-reg) :to :result)
- (new-stack :scs (descriptor-reg) :to :result))
- (:arg-types simple-array-unsigned-byte-32 simple-array-unsigned-byte-32)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
- (:save-p t)
- (:generator 25
- ;; Set up the return context.
- (inst push (make-fixup nil :code-object RETURN))
- (inst push ebp-tn)
- ;; Save the stack.
- (inst xor index index)
- ;; First, the stack-pointer.
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- esp-tn)
- (inst inc index)
- (inst mov stack (make-fixup (extern-alien-name "control_stack_end")
- :foreign))
- LOOP
- (inst cmp stack esp-tn)
- (inst jmp :le STACK-SAVE-DONE)
- (inst sub stack 4)
- (inst mov temp (make-ea :dword :base stack))
- (inst mov (make-ea :dword :base save-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type))
- temp)
- (inst inc index)
- (inst jmp-short LOOP)
-
- STACK-SAVE-DONE
- ;; Clean up the stack
- (inst add esp-tn 8)
-
- ;; Restore the new-stack.
- (inst xor index index)
- ;; First, the stack-pointer.
- (inst mov esp-tn
- (make-ea :dword :base new-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type)))
- (inst inc index)
- (inst mov stack (make-fixup (extern-alien-name "control_stack_end")
- :foreign))
- LOOP2
- (inst cmp stack esp-tn)
- (inst jmp :le STACK-RESTORE-DONE)
- (inst sub stack 4)
- (inst mov temp (make-ea :dword :base new-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset
- sb!vm:word-bytes)
- sb!vm:other-pointer-type)))
- (inst mov (make-ea :dword :base stack) temp)
- (inst inc index)
- (inst jmp-short LOOP2)
- STACK-RESTORE-DONE
- ;; Pop the frame pointer, and resume at the return address.
- (inst pop ebp-tn)
- (inst ret)
-
- ;; Original thread resumes, stack has been cleaned up.
- RETURN))
-
-(defknown control-stack-return ((simple-array (unsigned-byte 32) (*)))
- (values))
-
-(define-vop (control-stack-return)
+ (:translate %data-dependency-barrier)
+ (:generator 3))
+
+(define-vop (pause)
+ (:translate spin-loop-hint)
(:policy :fast-safe)
- (:translate control-stack-return)
- (:args (new-stack :scs (descriptor-reg) :to :result))
- (:arg-types simple-array-unsigned-byte-32)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
- (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
- (:save-p t)
- (:generator 25
- ;; Restore the new-stack.
- (inst xor index index)
- ;; First the stack-pointer.
- (inst mov esp-tn
- (make-ea :dword :base new-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset sb!vm:word-bytes)
- sb!vm:other-pointer-type)))
- (inst inc index)
- (inst mov stack (make-fixup (extern-alien-name "control_stack_end")
- :foreign))
- LOOP
- (inst cmp stack esp-tn)
- (inst jmp :le STACK-RESTORE-DONE)
- (inst sub stack 4)
- (inst mov temp (make-ea :dword :base new-stack :index index :scale 4
- :disp (- (* sb!vm:vector-data-offset
- sb!vm:word-bytes)
- sb!vm:other-pointer-type)))
- (inst mov (make-ea :dword :base stack) temp)
- (inst inc index)
- (inst jmp-short LOOP)
- STACK-RESTORE-DONE
- ;; Pop the frame pointer, and resume at the return address.
- (inst pop ebp-tn)
- (inst ret)))
+ (:generator 0
+ (inst pause)))