📄 call.lisp
字号:
;;; Non-TR local call for a fixed number of values passed according to the;;; unknown values convention.;;;;;; Args are the argument passing locations, which are specified only to;;; terminate their lifetimes in the caller.;;;;;; Values are the return value locations (wired to the standard passing;;; locations).;;;;;; Save is the save info, which we can ignore since saving has been done.;;; Return-PC is the TN that the return PC should be passed in.;;; Target is a continuation pointing to the start of the called function.;;; Nvals is the number of values received.;;;;;; Note: we can't use normal load-tn allocation for the fixed args, since all;;; registers may be tied up by the more operand. Instead, we use;;; MAYBE-LOAD-STACK-TN.;;;(define-vop (call-local) (:args (cfp) (nfp) (args :more t)) (:results (values :more t)) (:save-p t) (:move-args :local-call) (:info arg-locs callee target nvals) (:vop-var vop) (:temporary (:scs (descriptor-reg) :from :eval) move-temp) (:temporary (:scs (non-descriptor-reg)) temp) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) (:temporary (:sc any-reg :offset ocfp-offset :from :eval) ocfp) (:ignore arg-locs args ocfp) (:generator 5 (trace-table-entry trace-table-call-site) (let ((label (gen-label)) (cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn cfp) (inst compute-lra-from-code code-tn label temp (callee-return-pc-tn callee)) (note-this-location vop :call-site) (inst b target :nullify t) (emit-return-pc label) (default-unknown-values vop values nvals move-temp temp label) (when cur-nfp (load-stack-tn cur-nfp nfp-save))) (trace-table-entry trace-table-normal)));;; Non-TR local call for a variable number of return values passed according;;; to the unknown values convention. The results are the start of the values;;; glob and the number of values received.;;;;;; Note: we can't use normal load-tn allocation for the fixed args, since all;;; registers may be tied up by the more operand. Instead, we use;;; MAYBE-LOAD-STACK-TN.;;;(define-vop (multiple-call-local unknown-values-receiver) (:args (cfp) (nfp) (args :more t)) (:save-p t) (:move-args :local-call) (:info save callee target) (:ignore args save) (:vop-var vop) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) (:generator 20 (trace-table-entry trace-table-call-site) (let ((label (gen-label)) (cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn cfp) (inst compute-lra-from-code code-tn label temp (callee-return-pc-tn callee)) (note-this-location vop :call-site) (inst b target :nullify t) (emit-return-pc label) (note-this-location vop :unknown-return) (receive-unknown-values values-start nvals start count label temp) (when cur-nfp (load-stack-tn cur-nfp nfp-save))) (trace-table-entry trace-table-normal)));;;; Local call with known values return:;;; Non-TR local call with known return locations. Known-value return works;;; just like argument passing in local call.;;;;;; Note: we can't use normal load-tn allocation for the fixed args, since all;;; registers may be tied up by the more operand. Instead, we use;;; MAYBE-LOAD-STACK-TN.;;;(define-vop (known-call-local) (:args (cfp) (nfp) (args :more t)) (:results (res :more t)) (:move-args :local-call) (:save-p t) (:info save callee target) (:ignore args res save) (:vop-var vop) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) (:temporary (:scs (non-descriptor-reg)) temp) (:generator 5 (trace-table-entry trace-table-call-site) (let ((label (gen-label)) (cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn cfp) (inst compute-lra-from-code code-tn label temp (callee-return-pc-tn callee)) (note-this-location vop :call-site) (inst b target :nullify t) (emit-return-pc label) (note-this-location vop :known-return) (when cur-nfp (load-stack-tn cur-nfp nfp-save))) (trace-table-entry trace-table-normal)));;; Return from known values call. We receive the return locations as;;; arguments to terminate their lifetimes in the returning function. We;;; restore FP and CSP and jump to the Return-PC.;;;;;; Note: we can't use normal load-tn allocation for the fixed args, since all;;; registers may be tied up by the more operand. Instead, we use;;; MAYBE-LOAD-STACK-TN.;;;(define-vop (known-return) (:args (old-fp :target old-fp-temp) (return-pc :target return-pc-temp) (vals :more t)) (:temporary (:sc any-reg :from (:argument 0)) old-fp-temp) (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp) (:temporary (:scs (interior-reg)) lip) (:move-args :known-return) (:info val-locs) (:ignore val-locs vals) (:vop-var vop) (:generator 6 (trace-table-entry trace-table-fun-epilogue) (maybe-load-stack-tn old-fp-temp old-fp) (maybe-load-stack-tn return-pc-temp return-pc) (move cfp-tn csp-tn) (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (move cur-nfp nsp-tn))) (inst addi (- n-word-bytes other-pointer-lowtag) return-pc-temp lip) (inst bv lip) (move old-fp-temp cfp-tn) (trace-table-entry trace-table-normal)));;;; Full call:;;;;;; There is something of a cross-product effect with full calls. Different;;; versions are used depending on whether we know the number of arguments or;;; the name of the called function, and whether we want fixed values, unknown;;; values, or a tail call.;;;;;; In full call, the arguments are passed creating a partial frame on the;;; stack top and storing stack arguments into that frame. On entry to the;;; callee, this partial frame is pointed to by FP. If there are no stack;;; arguments, we don't bother allocating a partial frame, and instead set FP;;; to SP just before the call.;;; This macro helps in the definition of full call VOPs by avoiding code;;; replication in defining the cross-product VOPs.;;;;;; Name is the name of the VOP to define.;;;;;; Named is true if the first argument is a symbol whose global function;;; definition is to be called.;;;;;; Return is either :Fixed, :Unknown or :Tail:;;; -- If :Fixed, then the call is for a fixed number of values, returned in;;; the standard passing locations (passed as result operands).;;; -- If :Unknown, then the result values are pushed on the stack, and the;;; result values are specified by the Start and Count as in the;;; unknown-values continuation representation.;;; -- If :Tail, then do a tail-recursive call. No values are returned.;;; The Old-Fp and Return-PC are passed as the second and third arguments.;;;;;; In non-tail calls, the pointer to the stack arguments is passed as the last;;; fixed argument. If Variable is false, then the passing locations are;;; passed as a more arg. Variable is true if there are a variable number of;;; arguments passed on the stack. Variable cannot be specified with :Tail;;; return. TR variable argument call is implemented separately.;;;;;; In tail call with fixed arguments, the passing locations are passed as a;;; more arg, but there is no new-FP, since the arguments have been set up in;;; the current frame.;;;(macrolet ((define-full-call (name named return variable) (aver (not (and variable (eq return :tail)))) `(define-vop (,name ,@(when (eq return :unknown) '(unknown-values-receiver))) (:args ,@(unless (eq return :tail) '((new-fp :scs (any-reg) :to :eval))) ,(if named '(fdefn :target fdefn-pass) '(arg-fun :target lexenv)) ,@(when (eq return :tail) '((ocfp :target ocfp-pass) (lra :target lra-pass))) ,@(unless variable '((args :more t :scs (descriptor-reg))))) ,@(when (eq return :fixed) '((:results (values :more t)))) (:save-p ,(if (eq return :tail) :compute-only t)) ,@(unless (or (eq return :tail) variable) '((:move-args :full-call))) (:vop-var vop) (:info ,@(unless (or variable (eq return :tail)) '(arg-locs)) ,@(unless variable '(nargs)) ,@(when (eq return :fixed) '(nvals))) (:ignore ,@(unless (or variable (eq return :tail)) '(arg-locs)) ,@(unless variable '(args))) (:temporary (:sc descriptor-reg :offset ocfp-offset ,@(when (eq return :tail) '(:from (:argument 1))) ,@(unless (eq return :fixed) '(:to :eval))) ocfp-pass) (:temporary (:sc descriptor-reg :offset lra-offset ,@(when (eq return :tail) '(:from (:argument 2))) :to :eval) lra-pass) ,@(if named `((:temporary (:sc descriptor-reg :offset fdefn-offset :from (:argument ,(if (eq return :tail) 0 1)) :to :eval) fdefn-pass)) `((:temporary (:sc descriptor-reg :offset lexenv-offset :from (:argument ,(if (eq return :tail) 0 1)) :to :eval) lexenv) (:temporary (:scs (descriptor-reg) :from (:argument ,(if (eq return :tail) 2 1)) :to :eval) function))) (:temporary (:sc any-reg :offset nargs-offset :to :eval) nargs-pass) ,@(when variable (mapcar #'(lambda (name offset) `(:temporary (:sc descriptor-reg :offset ,offset :to :eval) ,name)) register-arg-names *register-arg-offsets*)) ,@(when (eq return :fixed) '((:temporary (:scs (descriptor-reg) :from :eval) move-temp))) ,@(unless (eq return :tail) '((:temporary (:scs (non-descriptor-reg)) temp) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save))) (:temporary (:scs (interior-reg) :type interior) lip) (:generator ,(+ (if named 5 0) (if variable 19 1) (if (eq return :tail) 0 10) 15 (if (eq return :unknown) 25 0)) (trace-table-entry trace-table-call-site) (let* ((cur-nfp (current-nfp-tn vop)) ,@(unless (eq return :tail) '((lra-label (gen-label)))) (filler (list :load-nargs ,@(if (eq return :tail) '((unless (location= ocfp ocfp-pass) :load-ocfp) (unless (location= lra lra-pass) :load-lra) (when cur-nfp :frob-nfp)) '((when cur-nfp :frob-nfp) :comp-lra :save-fp :load-fp))))) (labels ((do-next-filler () (when filler (ecase (pop filler) ((nil) (do-next-filler)) (:load-nargs ,@(if variable `((inst sub csp-tn new-fp nargs-pass) ,@(let ((index -1)) (mapcar #'(lambda (name) `(loadw ,name new-fp ,(incf index))) register-arg-names))) '((inst li (fixnumize nargs) nargs-pass)))) ,@(if (eq return :tail) '((:load-ocfp (sc-case ocfp (any-reg (inst move ocfp ocfp-pass)) (control-stack (loadw ocfp-pass cfp-tn (tn-offset ocfp))))) (:load-lra (sc-case lra (descriptor-reg (inst move lra lra-pass)) (control-stack (loadw lra-pass cfp-tn (tn-offset lra))))) (:frob-nfp (inst move cur-nfp nsp-tn))) `((:frob-nfp (store-stack-tn nfp-save cur-nfp)) (:comp-lra (inst compute-lra-from-code code-tn lra-label temp lra-pass)) (:save-fp (inst move cfp-tn ocfp-pass)) (:load-fp ,(if variable '(move new-fp cfp-tn) '(if (> nargs register-arg-count) (move new-fp cfp-tn) (move csp-tn cfp-tn)))))))))) ,@(if named `((sc-case fdefn (descriptor-reg (move fdefn fdefn-pass)) (control-stack (loadw fdefn-pass cfp-tn (tn-offset fdefn)) (do-next-filler)) (constant (loadw fdefn-pass code-tn (tn-offset fdefn) other-pointer-lowtag) (do-next-filler))) (loadw lip fdefn-pass fdefn-raw-addr-slot other-pointer-lowtag) (do-next-filler)) `((sc-case arg-fun (descriptor-reg (move arg-fun lexenv)) (control-stack (loadw lexenv cfp-tn (tn-offset arg-fun)) (do-next-filler)) (constant (loadw lexenv code-tn (tn-offset arg-fun) other-pointer-lowtag) (do-next-filler))) (loadw function lexenv closure-fun-slot fun-pointer-lowtag) (do-next-filler) (inst addi (- (ash simple-fun-code-offset word-shift) fun-pointer-lowtag) function lip))) (loop (cond ((null filler) (return)) ((null (car filler)) (pop filler)) ((null (cdr filler)) (return)) (t (do-next-filler)))) (note-this-location vop :call-site) (inst bv lip :nullify (null filler))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -