;;;; miscellaneous kernel-level definitions

;;;; 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!KERNEL")

;;; Return the 24 bits of data in the header of object X, which must
;;; be an other-pointer object.
(defun get-header-data (x)
  (get-header-data x))

;;; Set the 24 bits of data in the header of object X (which must be
;;; an other-pointer object) to VAL.
(defun set-header-data (x val)
  (set-header-data x val))

;;; Return the 24 bits of data in the header of object X, which must
;;; be a fun-pointer object.
;;;
;;; FIXME: Should this not be called GET-FUN-LENGTH instead? Or even better
;;; yet, if GET-HEADER-DATA masked the lowtag instead of substracting it, we
;;; could just use it instead -- or at least this could just be a function on
;;; top of the same VOP.
(defun get-closure-length (x)
  (get-closure-length x))

(defun lowtag-of (x)
  (lowtag-of x))

(defun widetag-of (x)
  (widetag-of x))

;;; WIDETAG-OF needs extra code to handle LIST and FUNCTION lowtags. When
;;; we're only dealing with other pointers (eg. when dispatching on array
;;; element type), this is going to be faster.
(declaim (inline %other-pointer-widetag))
(defun %other-pointer-widetag (x)
  (sb!sys:sap-ref-8 (int-sap (get-lisp-obj-address x))
                    #.(ecase sb!c:*backend-byte-order*
                        (:little-endian
                         (- sb!vm:other-pointer-lowtag))
                        (:big-endian
                         (- (1- sb!vm:n-word-bytes) sb!vm:other-pointer-lowtag)))))

;;; Return a System-Area-Pointer pointing to the data for the vector
;;; X, which must be simple.
;;;
;;; FIXME: So it should be SIMPLE-VECTOR-SAP, right? (or UNHAIRY-VECTOR-SAP,
;;; if the meaning is (SIMPLE-ARRAY * 1) instead of SIMPLE-VECTOR)
;;; (or maybe SIMPLE-VECTOR-DATA-SAP or UNHAIRY-VECTOR-DATA-SAP?)
(defun vector-sap (x)
  (declare (type (simple-unboxed-array (*)) x))
  (vector-sap x))

;;; Return a System-Area-Pointer pointing to the end of the binding stack.
(defun sb!c::binding-stack-pointer-sap ()
  (sb!c::binding-stack-pointer-sap))

;;; Return a System-Area-Pointer pointing to the next free word of the
;;; current dynamic space.
(defun sb!c::dynamic-space-free-pointer ()
  (sb!c::dynamic-space-free-pointer))

;;; Return a System-Area-Pointer pointing to the end of the control stack.
(defun sb!c::control-stack-pointer-sap ()
  (sb!c::control-stack-pointer-sap))

;;; Return the header typecode for FUNCTION. Can be set with SETF.
(defun fun-subtype (function)
  (fun-subtype function))
(defun (setf fun-subtype) (type function)
  (setf (fun-subtype function) type))

;;;; SIMPLE-FUN and accessors

(declaim (inline simple-fun-p))
(defun simple-fun-p (object)
  (= sb!vm:simple-fun-header-widetag (widetag-of object)))

(deftype simple-fun ()
  '(satisfies simple-fun-p))

(defun %simple-fun-doc (simple-fun)
  (declare (simple-fun simple-fun))
  (let ((info (%simple-fun-info simple-fun)))
    (cond ((typep info '(or null string))
           info)
          ((simple-vector-p info)
           nil)
          ((consp info)
           (car info))
          (t
           (bug "bogus INFO for ~S: ~S" simple-fun info)))))

(defun (setf %simple-fun-doc) (doc simple-fun)
  (declare (type (or null string) doc)
           (simple-fun simple-fun))
  (let ((info (%simple-fun-info simple-fun)))
    (setf (%simple-fun-info simple-fun)
          (cond ((typep info '(or null string))
                 doc)
                ((simple-vector-p info)
                 (if doc
                     (cons doc info)
                     info))
                ((consp info)
                 (if doc
                     (cons doc (cdr info))
                     (cdr info)))
                (t
                 (bug "bogus INFO for ~S: ~S" simple-fun info))))))

(defun %simple-fun-xrefs (simple-fun)
  (declare (simple-fun simple-fun))
  (let ((info (%simple-fun-info simple-fun)))
    (cond ((typep info '(or null string))
           nil)
          ((simple-vector-p info)
           info)
          ((consp info)
           (cdr info))
          (t
           (bug "bogus INFO for ~S: ~S" simple-fun info)))))

;;; Extract the arglist from the function header FUNC.
(defun %simple-fun-arglist (func)
  (%simple-fun-arglist func))

(defun (setf %simple-fun-arglist) (new-value func)
  (setf (%simple-fun-arglist func) new-value))

;;; Extract the name from the function header FUNC.
(defun %simple-fun-name (func)
  (%simple-fun-name func))

(defun (setf %simple-fun-name) (new-value func)
  (setf (%simple-fun-name func) new-value))

;;; Extract the type from the function header FUNC.
(defun %simple-fun-type (func)
  (%simple-fun-type func))

(defun %simple-fun-next (simple-fun)
  (%simple-fun-next simple-fun))

(defun %simple-fun-self (simple-fun)
  (%simple-fun-self simple-fun))

;;;; CLOSURE type and accessors

(declaim (inline closurep))
(defun closurep (object)
  (= sb!vm:closure-header-widetag (widetag-of object)))

(deftype closure ()
  '(satisfies closurep))

(defmacro do-closure-values ((value closure) &body body)
  (with-unique-names (i nclosure)
    `(let ((,nclosure ,closure))
       (declare (closure ,nclosure))
       (dotimes (,i (- (1+ (get-closure-length ,nclosure)) sb!vm:closure-info-offset))
         (let ((,value (%closure-index-ref ,nclosure ,i)))
           ,@body)))))

(defun %closure-values (closure)
  (declare (closure closure))
  (let (values)
    (do-closure-values (elt closure)
      (push elt values))
    (nreverse values)))

;;; Extract the function from CLOSURE.
(defun %closure-fun (closure)
  (%closure-fun closure))

;;; Extract the INDEXth slot from CLOSURE.
(defun %closure-index-ref (closure index)
  (%closure-index-ref closure index))

;;; Return the length of VECTOR. There is no reason to use this in
;;; ordinary code, 'cause length (the vector foo)) is the same.
(defun sb!c::vector-length (vector)
  (sb!c::vector-length vector))

;;; Allocate a unboxed, simple vector with type code TYPE, length LENGTH, and
;;; WORDS words long. Note: it is your responsibility to ensure that the
;;; relation between LENGTH and WORDS is correct.
(defun allocate-vector (type length words)
  (allocate-vector type length words))

;;; Allocate an array header with type code TYPE and rank RANK.
(defun make-array-header (type rank)
  (make-array-header type rank))

;;; Return a SAP pointing to the instructions part of CODE-OBJ.
(defun code-instructions (code-obj)
  (code-instructions code-obj))

;;; Extract the INDEXth element from the header of CODE-OBJ. Can be
;;; set with SETF.
(defun code-header-ref (code-obj index)
  (code-header-ref code-obj index))

(defun code-header-set (code-obj index new)
  (code-header-set code-obj index new))

(defun %vector-raw-bits (object offset)
  (declare (type index offset))
  (sb!kernel:%vector-raw-bits object offset))

(defun %set-vector-raw-bits (object offset value)
  (declare (type index offset))
  (declare (type sb!vm:word value))
  (setf (sb!kernel:%vector-raw-bits object offset) value))

(defun make-single-float (x) (make-single-float x))
(defun make-double-float (hi lo) (make-double-float hi lo))

(defun single-float-bits (x) (single-float-bits x))
(defun double-float-high-bits (x) (double-float-high-bits x))
(defun double-float-low-bits (x) (double-float-low-bits x))

