;;; Return a wired TN describing the N'th full call argument passing
;;; location.
-(!def-vm-support-routine standard-arg-location (n)
+(defun standard-arg-location (n)
(declare (type unsigned-byte n))
(if (< n register-arg-count)
(make-wired-tn *backend-t-primitive-type*
;;; true, then use the standard (full call) location, otherwise use any legal
;;; location. Even in the non-standard case, this may be restricted by a
;;; desire to use a subroutine call instruction.
-(!def-vm-support-routine make-return-pc-passing-location (standard)
+(defun make-return-pc-passing-location (standard)
(if standard
(make-wired-tn *backend-t-primitive-type* register-arg-scn lra-offset)
(make-restricted-tn *backend-t-primitive-type* register-arg-scn)))
;;; standard convention, but is totally unrestricted in non-standard
;;; conventions, since we can always fetch it off of the stack using
;;; the arg pointer.
-(!def-vm-support-routine make-old-fp-passing-location (standard)
+(defun make-old-fp-passing-location (standard)
(if standard
(make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)
(make-normal-tn *fixnum-primitive-type*)))
;;; Make the TNs used to hold OLD-FP and RETURN-PC within the current
;;; function. We treat these specially so that the debugger can find
;;; them at a known location.
-(!def-vm-support-routine make-old-fp-save-location (env)
+(defun make-old-fp-save-location (env)
(specify-save-tn
(physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env)
(make-wired-tn *fixnum-primitive-type*
control-stack-arg-scn
ocfp-save-offset)))
-(!def-vm-support-routine make-return-pc-save-location (env)
+
+(defun make-return-pc-save-location (env)
(let ((ptype *backend-t-primitive-type*))
(specify-save-tn
(physenv-debug-live-tn (make-normal-tn ptype) env)
;;; Make a TN for the standard argument count passing location. We only
;;; need to make the standard location, since a count is never passed when we
;;; are using non-standard conventions.
-(!def-vm-support-routine make-arg-count-location ()
+(defun make-arg-count-location ()
(make-wired-tn *fixnum-primitive-type* immediate-arg-scn nargs-offset))
;;; Make a TN to hold the number-stack frame pointer. This is allocated
;;; once per component, and is component-live.
-(!def-vm-support-routine make-nfp-tn ()
+(defun make-nfp-tn ()
(component-live-tn
(make-wired-tn *fixnum-primitive-type* immediate-arg-scn nfp-offset)))
-(!def-vm-support-routine make-stack-pointer-tn ()
+(defun make-stack-pointer-tn ()
(make-normal-tn *fixnum-primitive-type*))
-(!def-vm-support-routine make-number-stack-pointer-tn ()
+(defun make-number-stack-pointer-tn ()
(make-normal-tn *fixnum-primitive-type*))
;;; Return a list of TNs that can be used to represent an unknown-values
;;; continuation within a function.
-(!def-vm-support-routine make-unknown-values-locations ()
+(defun make-unknown-values-locations ()
(list (make-stack-pointer-tn)
(make-normal-tn *fixnum-primitive-type*)))
;;; VM-dependent initialization of the IR2-COMPONENT structure. We push
;;; placeholder entries in the Constants to leave room for additional
;;; noise in the code object header.
-(!def-vm-support-routine select-component-format (component)
+(defun select-component-format (component)
(declare (type component component))
(dotimes (i code-constants-offset)
(vector-push-extend nil
(when nfp
(inst addu val nfp (bytes-needed-for-non-descriptor-stack-frame))))))
+;;; Accessing a slot from an earlier stack frame is definite hackery.
+(define-vop (ancestor-frame-ref)
+ (:args (frame-pointer :scs (descriptor-reg))
+ (variable-home-tn :load-if nil))
+ (:results (value :scs (descriptor-reg any-reg)))
+ (:policy :fast-safe)
+ (:generator 4
+ (aver (sc-is variable-home-tn control-stack))
+ (loadw value frame-pointer (tn-offset variable-home-tn))))
+(define-vop (ancestor-frame-set)
+ (:args (frame-pointer :scs (descriptor-reg))
+ (value :scs (descriptor-reg any-reg)))
+ (:results (variable-home-tn :load-if nil))
+ (:policy :fast-safe)
+ (:generator 4
+ (aver (sc-is variable-home-tn control-stack))
+ (storew value frame-pointer (tn-offset variable-home-tn))))
(define-vop (xep-allocate-frame)
(:info start-lab copy-more-arg-follows)
(:generator 1
;; Make sure the function is aligned, and drop a label pointing to this
;; function header.
- (align n-lowtag-bits)
+ (emit-alignment n-lowtag-bits)
(trace-table-entry trace-table-fun-prologue)
(emit-label start-lab)
;; Allocate function header.
;; gets confused.
(without-scheduling ()
(note-this-location vop :single-value-return)
- (inst move csp-tn ocfp-tn)
+ (move csp-tn ocfp-tn t)
(inst nop))
(when lra-label
(inst compute-code-from-lra code-tn code-tn lra-label temp)))
(aver defaults)
(assemble (*elsewhere*)
(emit-label default-stack-vals)
+ (trace-table-entry trace-table-fun-prologue)
(do ((remaining defaults (cdr remaining)))
((null remaining))
(let ((def (car remaining)))
(emit-label (car def))
(when (null (cdr remaining))
(inst b defaulting-done))
- (store-stack-tn (cdr def) null-tn)))))))
+ (store-stack-tn (cdr def) null-tn)))
+ (trace-table-entry trace-table-normal)))))
(when lra-label
(inst compute-code-from-lra code-tn code-tn lra-label temp))))
(when lra-label
(inst compute-code-from-lra code-tn code-tn lra-label temp))
- (inst addu csp-tn csp-tn 4)
+ (inst addu csp-tn csp-tn n-word-bytes)
(storew (first *register-arg-tns*) csp-tn -1)
- (inst addu start csp-tn -4)
+ (inst addu start csp-tn (- n-word-bytes))
(inst li count (fixnumize 1))
(emit-label done)
nvals)
(:temporary (:scs (non-descriptor-reg)) temp))
+\f
+;;; This hook in the codegen pass lets us insert code before fall-thru entry
+;;; points, local-call entry points, and tail-call entry points. The default
+;;; does nothing.
+(defun emit-block-header (start-label trampoline-label fall-thru-p alignp)
+ (declare (ignore fall-thru-p alignp))
+ (when trampoline-label
+ (emit-label trampoline-label))
+ (emit-label start-label))
\f
;;;; Local call with unknown values convention return:
(:ignore args save)
(:vop-var vop)
(:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
+ (:temporary (:scs (non-descriptor-reg)) temp)
(:generator 20
(let ((label (gen-label))
(cur-nfp (current-nfp-tn vop)))
(:vop-var vop)
(:info ,@(unless (or variable (eq return :tail)) '(arg-locs))
,@(unless variable '(nargs))
- ,@(when (eq return :fixed) '(nvals)))
+ ,@(when (eq return :fixed) '(nvals))
+ step-instrumenting)
(:ignore ,@(unless (or variable (eq return :tail)) '(arg-locs))
,@(unless variable '(args)))
,@(when (eq return :fixed)
'((:temporary (:scs (descriptor-reg) :from :eval) move-temp)))
+ (:temporary (:scs (descriptor-reg) :to :eval) stepping)
+
,@(unless (eq return :tail)
'((:temporary (:scs (non-descriptor-reg)) temp)
(:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)))
- (:temporary (:sc interior-reg :offset lip-offset) entry-point)
+ (:temporary (:sc interior-reg) entry-point)
(:generator ,(+ (if named 5 0)
(if variable 19 1)
(let* ((cur-nfp (current-nfp-tn vop))
,@(unless (eq return :tail)
'((lra-label (gen-label))))
+ (step-done-label (gen-label))
(filler
(remove nil
(list :load-nargs
(move cfp-tn csp-tn)))
(trace-table-entry trace-table-call-site))))
((nil)
- (inst nop))))))
+ (inst nop)))))
+ (insert-step-instrumenting (callable-tn)
+ ;; Conditionally insert a conditional trap:
+ (when step-instrumenting
+ (load-symbol-value stepping sb!impl::*stepping*)
+ ;; If it's not NIL, trap.
+ (inst beq stepping null-tn step-done-label)
+ (inst nop)
+ ;; CONTEXT-PC will be pointing here when the
+ ;; interrupt is handled, not after the BREAK.
+ (note-this-location vop :step-before-vop)
+ ;; Construct a trap code with the low bits from
+ ;; SINGLE-STEP-AROUND-TRAP and the high bits from
+ ;; the register number of CALLABLE-TN.
+ (inst break 0 (logior single-step-around-trap
+ (ash (reg-tn-encoding callable-tn)
+ 5)))
+ (emit-label step-done-label))))
,@(if named
`((sc-case name
(- (ash (tn-offset name) word-shift)
other-pointer-lowtag))
(do-next-filler)))
+ ;; The step instrumenting must be done after
+ ;; FUNCTION is loaded, but before ENTRY-POINT is
+ ;; calculated.
+ (insert-step-instrumenting name-pass)
(inst lw entry-point name-pass
(- (ash fdefn-raw-addr-slot word-shift)
other-pointer-lowtag))
(- (ash closure-fun-slot word-shift)
fun-pointer-lowtag))
(do-next-filler)
+ ;; The step instrumenting must be done before
+ ;; after FUNCTION is loaded, but before ENTRY-POINT
+ ;; is calculated.
+ (insert-step-instrumenting function)
(inst addu entry-point function
(- (ash simple-fun-code-offset word-shift)
fun-pointer-lowtag))))
(when cur-nfp
(inst addu nsp-tn cur-nfp
(bytes-needed-for-non-descriptor-stack-frame))))
- ;; Establish the values pointer and values count.
- (move val-ptr cfp-tn)
- (inst li nargs (fixnumize nvals))
- ;; restore the frame pointer and clear as much of the control
- ;; stack as possible.
- (move cfp-tn ocfp)
- (inst addu csp-tn val-ptr (* nvals n-word-bytes))
- ;; pre-default any argument register that need it.
- (when (< nvals register-arg-count)
- (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals))
- (move reg null-tn)))
- ;; And away we go.
- (lisp-return return-pc lip)
+ (cond ((= nvals 1)
+ ;; Clear the control stack, and restore the frame pointer.
+ (move csp-tn cfp-tn)
+ (move cfp-tn ocfp)
+ ;; Out of here.
+ (lisp-return return-pc lip :offset 2))
+ (t
+ ;; Establish the values pointer and values count.
+ (move val-ptr cfp-tn)
+ (inst li nargs (fixnumize nvals))
+ ;; restore the frame pointer and clear as much of the control
+ ;; stack as possible.
+ (move cfp-tn ocfp)
+ (inst addu csp-tn val-ptr (* nvals n-word-bytes))
+ ;; pre-default any argument register that need it.
+ (when (< nvals register-arg-count)
+ (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals))
+ (move reg null-tn)))
+ ;; And away we go.
+ (lisp-return return-pc lip)))
(trace-table-entry trace-table-normal)))
;;; Do unknown-values return of an arbitrary number of values (passed on the
(emit-label done))))
-;;; More args are stored consequtively on the stack, starting immediately at
-;;; the context pointer. The context pointer is not typed, so the lowtag is 0.
-;;;
+;;; More args are stored consecutively on the stack, starting
+;;; immediately at the context pointer. The context pointer is not
+;;; typed, so the lowtag is 0.
(define-full-reffer more-arg * 0 0 (descriptor-reg any-reg) * %more-arg)
-
;;; Turn more arg (context, count) into a list.
-;;;
(define-vop (listify-rest-args)
(:args (context-arg :target context :scs (descriptor-reg))
(count-arg :target count :scs (any-reg)))
(:results (result :scs (descriptor-reg)))
(:translate %listify-rest-args)
(:policy :safe)
+ (:node-var node)
(:generator 20
- (let ((enter (gen-label))
- (loop (gen-label))
- (done (gen-label)))
+ (let* ((enter (gen-label))
+ (loop (gen-label))
+ (done (gen-label))
+ (dx-p (node-stack-allocate-p node))
+ (alloc-area-tn (if dx-p csp-tn alloc-tn)))
(move context context-arg)
(move count count-arg)
;; Check to see if there are any arguments.
- (inst beq count zero-tn done)
+ (inst beq count done)
(move result null-tn t)
;; We need to do this atomically.
(pseudo-atomic (pa-flag)
+ (when dx-p
+ (align-csp temp))
;; Allocate a cons (2 words) for each item.
- (inst or result alloc-tn list-pointer-lowtag)
+ (inst srl result alloc-area-tn n-lowtag-bits)
+ (inst sll result n-lowtag-bits)
+ (inst or result list-pointer-lowtag)
(move dst result)
(inst sll temp count 1)
(inst b enter)
- (inst addu alloc-tn alloc-tn temp)
+ (inst addu alloc-area-tn temp)
;; Store the current cons in the cdr of the previous cons.
(emit-label loop)
(emit-label enter)
;; Grab one value.
(loadw temp context)
- (inst addu context context n-word-bytes)
+ (inst addu context n-word-bytes)
;; Dec count, and if != zero, go back for more.
(inst addu count count (fixnumize -1))
- (inst bne count zero-tn loop)
+ (inst bne count loop)
;; Store the value in the car (in delay slot)
(storew temp dst 0 list-pointer-lowtag)
(let ((err-lab
(generate-error-code vop invalid-arg-count-error nargs)))
(cond ((zerop count)
- (inst bne nargs zero-tn err-lab)
+ (inst bne nargs err-lab)
(inst nop))
(t
(inst li temp (fixnumize count))
(frob unknown-key-arg-error unknown-key-arg-error
sb!c::%unknown-key-arg-error key)
(frob nil-fun-returned-error nil-fun-returned-error nil fun))
+
+;;; Single-stepping
+
+(define-vop (step-instrument-before-vop)
+ (:temporary (:scs (descriptor-reg)) stepping)
+ (:policy :fast-safe)
+ (:vop-var vop)
+ (:generator 3
+ (load-symbol-value stepping sb!impl::*stepping*)
+ ;; If it's not NIL, trap.
+ (inst beq stepping null-tn DONE)
+ (inst nop)
+ ;; CONTEXT-PC will be pointing here when the interrupt is handled,
+ ;; not after the BREAK.
+ (note-this-location vop :step-before-vop)
+ ;; CALLEE-REGISTER-OFFSET isn't needed for before-traps, so we
+ ;; can just use a bare SINGLE-STEP-BEFORE-TRAP as the code.
+ (inst break 0 single-step-before-trap)
+ DONE))