;;;; Code in this file handles VM-independent details of run-time
;;;; function representation that primarily concern IR2 conversion and
;;;; the dumper/loader.

;;;; This software is part of the SBCL system. See the README file for
;;;; more information.
;;;;
;;;; This software is derived from the CMU CL system, which was
;;;; written at Carnegie Mellon University and released into the
;;;; public domain. The software is in the public domain and is
;;;; provided with absolutely no warranty. See the COPYING and CREDITS
;;;; files for more information.

(in-package "SB!C")

;;; This phase runs before IR2 conversion, initializing each XEP's
;;; ENTRY-INFO structure. We call the VM-supplied
;;; SELECT-COMPONENT-FORMAT function to make VM-dependent
;;; initializations in the IR2-COMPONENT. This includes setting the
;;; IR2-COMPONENT-KIND and allocating fixed implementation overhead in
;;; the constant pool. If there was a forward reference to a function,
;;; then the ENTRY-INFO will already exist, but will be uninitialized.
(defun entry-analyze (component)
  (let ((2comp (component-info component)))
    (dolist (fun (component-lambdas component))
      (when (xep-p fun)
        (let ((info (or (leaf-info fun)
                        (setf (leaf-info fun) (make-entry-info)))))
          (compute-entry-info fun info)
          (push info (ir2-component-entries 2comp))))))
  (select-component-format component)
  (values))

;;; Initialize INFO structure to correspond to the XEP LAMBDA FUN.
(defun compute-entry-info (fun info)
  (declare (type clambda fun) (type entry-info info))
  (let ((bind (lambda-bind fun))
        (internal-fun (functional-entry-fun fun)))
    (setf (entry-info-closure-tn info)
          (if (physenv-closure (lambda-physenv fun))
              (make-normal-tn *backend-t-primitive-type*)
              nil))
    (setf (entry-info-offset info) (gen-label))
    (setf (entry-info-name info)
          (leaf-debug-name internal-fun))
    (let ((doc (functional-documentation internal-fun))
          (xrefs (pack-xref-data (functional-xref internal-fun))))
      (setf (entry-info-info info) (if (and doc xrefs)
                                       (cons doc xrefs)
                                       (or doc xrefs))))
    (when (policy bind (>= debug 1))
      (let ((args (functional-arg-documentation internal-fun)))
        ;; When the component is dumped, the arglists of the entry
        ;; points will be dumped.  If they contain values that need
        ;; make-load-form processing then we need to do it now (bug
        ;; 310132).
        (setf (entry-info-arguments info)
              (constant-value (find-constant args))))
      ;; Arguably we should not parse/unparse if the type was obtained from
      ;; a proclamation. On the other hand, this preserves exact semantics
      ;; if a later DEFTYPE changes something. Be that as it may, storing
      ;; just <X> instead of (VALUES <X> &OPTIONAL) saves 6 words per entry.
      (let ((spec (type-specifier (leaf-type internal-fun)))
            (result))
        (setf (entry-info-type info)
              (if (and (listp spec)
                       (typep (setq result (third spec))
                              '(cons (eql values)
                                     (cons t (cons (eql &optional) null)))))
                  `(sfunction ,(cadr spec) ,(cadr result))
                  spec)))))
  (values))

;;; Replace all references to COMPONENT's non-closure XEPs that appear
;;; in top level or externally-referenced components, changing to
;;; :TOPLEVEL-XEP FUNCTIONALs. If the cross-component ref is not in a
;;; :TOPLEVEL/externally-referenced component, or is to a closure,
;;; then substitution is suppressed.
;;;
;;; When a cross-component ref is not substituted, we return T to
;;; indicate that early deletion of this component's IR1 should not be
;;; done. We also return T if this component contains
;;; :TOPLEVEL/externally-referenced lambdas (though it is not a
;;; :TOPLEVEL component.)
;;;
;;; We deliberately don't use the normal reference deletion, since we
;;; don't want to trigger deletion of the XEP (although it shouldn't
;;; hurt, since this is called after COMPONENT is compiled.) Instead,
;;; we just clobber the REF-LEAF.
(defun replace-toplevel-xeps (component)
  (let ((res nil))
    (dolist (lambda (component-lambdas component))
      (case (functional-kind lambda)
        (:external
         (unless (lambda-has-external-references-p lambda)
           (let* ((ef (functional-entry-fun lambda))
                  (new (make-functional
                        :kind :toplevel-xep
                        :info (leaf-info lambda)
                        :%source-name (functional-%source-name ef)
                        :%debug-name (functional-%debug-name ef)
                        :lexenv (make-null-lexenv)))
                  (closure (physenv-closure
                            (lambda-physenv (main-entry ef)))))
             (dolist (ref (leaf-refs lambda))
               (let ((ref-component (node-component ref)))
                 (cond ((eq ref-component component))
                       ((or (not (component-toplevelish-p ref-component))
                            closure)
                        (setq res t))
                       (t
                        (setf (ref-leaf ref) new)
                        (push ref (leaf-refs new))
                        (setf (leaf-refs lambda)
                              (delq ref (leaf-refs lambda))))))))))
        (:toplevel
         (setq res t))))
    res))
