call.lisp
来自「开源跨平台Lisp编译器」· LISP 代码 · 共 1,244 行 · 第 1/4 页
LISP
1,244 行
(store-stack-tn tn move-temp))) (emit-label defaulting-done) (move ocfp-tn csp-tn) (let ((defaults (defaults))) (aver defaults) (assemble (*elsewhere*) (emit-label default-stack-vals) (do ((remaining defaults (cdr remaining))) ((null remaining)) (let ((def (car remaining))) (emit-label (car def)) (store-stack-tn (cdr def) null-tn))) (inst br zero-tn defaulting-done))))) (when lra-label (inst compute-code-from-lra code-tn code-tn lra-label temp)))) (values));;;; unknown values receiving;;; Emit code needed at the return point for an unknown-values call;;; for an arbitrary number of values.;;;;;; We do the single and non-single cases with no shared code: there;;; doesn't seem to be any potential overlap, and receiving a single;;; value is more important efficiency-wise.;;;;;; When there is a single value, we just push it on the stack,;;; returning the old SP and 1.;;;;;; When there is a variable number of values, we move all of the;;; argument registers onto the stack, and return Args and Nargs.;;;;;; Args and Nargs are TNs wired to the named locations. We must;;; explicitly allocate these TNs, since their lifetimes overlap with;;; the results Start and Count (also, it's nice to be able to target;;; them).(defun receive-unknown-values (args nargs start count lra-label temp) (declare (type tn args nargs start count temp)) (let ((variable-values (gen-label)) (done (gen-label))) (without-scheduling () (inst br zero-tn variable-values) (inst nop)) (when lra-label (inst compute-code-from-lra code-tn code-tn lra-label temp)) (inst addq csp-tn 4 csp-tn) (storew (first *register-arg-tns*) csp-tn -1) (inst subq csp-tn 4 start) (inst li (fixnumize 1) count) (emit-label done) (assemble (*elsewhere*) (emit-label variable-values) (when lra-label (inst compute-code-from-lra code-tn code-tn lra-label temp)) (do ((arg *register-arg-tns* (rest arg)) (i 0 (1+ i))) ((null arg)) (storew (first arg) args i)) (move args start) (move nargs count) (inst br zero-tn done))) (values));;; a VOP that can be inherited by unknown values receivers. The main;;; thing this handles is allocation of the result temporaries.(define-vop (unknown-values-receiver) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:temporary (:sc descriptor-reg :offset ocfp-offset :from :eval :to (:result 0)) values-start) (:temporary (:sc any-reg :offset nargs-offset :from :eval :to (:result 1)) nvals) (:temporary (:scs (non-descriptor-reg)) temp));;;; local call with unknown values convention return;;; 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 (fp) (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 (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))) (maybe-load-stack-nfp-tn callee-nfp nfp temp)) (maybe-load-stack-tn cfp-tn fp) (trace-table-entry trace-table-call-site) (inst compute-lra-from-code (callee-return-pc-tn callee) code-tn label temp) (note-this-location vop :call-site) (inst br zero-tn target) (trace-table-entry trace-table-normal) (emit-return-pc label) (default-unknown-values vop values nvals move-temp temp label) (maybe-load-stack-nfp-tn cur-nfp nfp-save temp))));;; 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 (fp) (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) (:temporary (:scs (non-descriptor-reg)) temp) (:generator 20 (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))) (maybe-load-stack-nfp-tn callee-nfp nfp temp)) (maybe-load-stack-tn cfp-tn fp) (trace-table-entry trace-table-call-site) (inst compute-lra-from-code (callee-return-pc-tn callee) code-tn label temp) (note-this-location vop :call-site) (inst bsr zero-tn target) (trace-table-entry trace-table-normal) (emit-return-pc label) (note-this-location vop :unknown-return) (receive-unknown-values values-start nvals start count label temp) (maybe-load-stack-nfp-tn cur-nfp nfp-save temp))));;;; 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 (fp) (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 (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))) (maybe-load-stack-nfp-tn callee-nfp nfp temp)) (maybe-load-stack-tn cfp-tn fp) (trace-table-entry trace-table-call-site) (inst compute-lra-from-code (callee-return-pc-tn callee) code-tn label temp) (note-this-location vop :call-site) (inst bsr zero-tn target) (trace-table-entry trace-table-normal) (emit-return-pc label) (note-this-location vop :known-return) (maybe-load-stack-nfp-tn cur-nfp nfp-save temp))));;; 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 (ocfp :target ocfp-temp) (return-pc :target return-pc-temp) (vals :more t)) (:temporary (:sc any-reg :from (:argument 0)) ocfp-temp) (:temporary (:sc any-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 ocfp-temp ocfp) (maybe-load-stack-tn return-pc-temp return-pc) (move cfp-tn csp-tn) (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (inst addq cur-nfp (bytes-needed-for-non-descriptor-stack-frame) nsp-tn))) (inst subq return-pc-temp (- other-pointer-lowtag n-word-bytes) lip) (move ocfp-temp cfp-tn) (inst ret zero-tn lip 1) (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 Ocfp 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.(defmacro 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 '(name :target name-pass) '(arg-fun :target lexenv)) ,@(when (eq return :tail) '((ocfp :target ocfp-pass) (return-pc :target return-pc-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)))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?