;;;
;;; Copyright 2005-2009 Clozure Associates
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;;     http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.


(in-package "CCL")


(defun %frame-backlink (p &optional context)
  (declare (ignore context))
  (cond ((fixnump p) (%%frame-backlink p))
        (t (error "~s is not a valid stack frame" p))))

(defun bottom-of-stack-p (p context)
  (and (fixnump p)
       (locally (declare (fixnum p))
	 (let* ((tcr (if context (bt.tcr context) (%current-tcr)))
                (vs-area (%fixnum-ref tcr (- target::tcr.vs-area
					     target::tcr-bias))))
	   (not (%ptr-in-area-p p vs-area))))))


(defun lisp-frame-p (p context)
  (declare (fixnum p))
  (let ((next-frame (%frame-backlink p context)))
    (declare (fixnum next-frame))
    (if (bottom-of-stack-p next-frame context)
        (values nil t)
        (values t nil))))


(defun catch-frame-sp (catch)
  (uvref catch
	 #+x8632-target x8632::catch-frame.ebp-cell
	 #+x8664-target x8664::catch-frame.rbp-cell))

;;; Sure would be nice to have &optional in defppclapfunction arglists
;;; Sure would be nice not to do this at runtime.

(let ((bits (lfun-bits #'(lambda (x &optional y) (declare (ignore x y))))))
  (lfun-bits #'%fixnum-ref
             (dpb (ldb $lfbits-numreq bits)
                  $lfbits-numreq
                  (dpb (ldb $lfbits-numopt bits)
                       $lfbits-numopt
                       (lfun-bits #'%fixnum-ref)))))

(let ((bits (lfun-bits #'(lambda (x &optional y) (declare (ignore x y))))))
  (lfun-bits #'%fixnum-ref-natural
             (dpb (ldb $lfbits-numreq bits)
                  $lfbits-numreq
                  (dpb (ldb $lfbits-numopt bits)
                       $lfbits-numopt
                       (lfun-bits #'%fixnum-ref-natural)))))


;;; Sure would be nice to have &optional in defppclapfunction arglists
;;; Sure would be nice not to do this at runtime.

(let ((bits (lfun-bits #'(lambda (x &optional y) (declare (ignore x y))))))
  (lfun-bits #'%fixnum-ref
             (dpb (ldb $lfbits-numreq bits)
                  $lfbits-numreq
                  (dpb (ldb $lfbits-numopt bits)
                       $lfbits-numopt
                       (lfun-bits #'%fixnum-ref)))))

(let ((bits (lfun-bits #'(lambda (x &optional y) (declare (ignore x y))))))
  (lfun-bits #'%fixnum-ref-natural
             (dpb (ldb $lfbits-numreq bits)
                  $lfbits-numreq
                  (dpb (ldb $lfbits-numopt bits)
                       $lfbits-numopt
                       (lfun-bits #'%fixnum-ref-natural)))))

(let ((bits (lfun-bits #'(lambda (x y &optional z) (declare (ignore x y z))))))
  (lfun-bits #'%fixnum-set
             (dpb (ldb $lfbits-numreq bits)
                  $lfbits-numreq
                  (dpb (ldb $lfbits-numopt bits)
                       $lfbits-numopt
                       (lfun-bits #'%fixnum-set)))))

(let ((bits (lfun-bits #'(lambda (x y &optional z) (declare (ignore x y z))))))
  (lfun-bits #'%fixnum-set-natural
             (dpb (ldb $lfbits-numreq bits)
                  $lfbits-numreq
                  (dpb (ldb $lfbits-numopt bits)
                       $lfbits-numopt
                       (lfun-bits #'%fixnum-set-natural)))))


#+x8632-target
(defun valid-subtag-p (subtag)
  (declare (fixnum subtag))
  (let* ((tagval (ldb (byte (- x8632::num-subtag-bits x8632::ntagbits) x8632::ntagbits) subtag)))
    (declare (fixnum tagval))
    (case (logand subtag x8632::fulltagmask)
      (#. x8632::fulltag-immheader (not (eq (%svref *immheader-types* tagval) 'bogus)))
      (#. x8632::fulltag-nodeheader (not (eq (%svref *nodeheader-types* tagval) 'bogus)))
      (t nil))))

#+x8664-target
(defun valid-subtag-p (subtag)
  (declare (fixnum subtag))
  (let* ((tagval (logand x8664::fulltagmask subtag))
         (high4 (ash subtag (- x8664::ntagbits))))
    (declare (fixnum tagval high4))
    (not (eq 'bogus
             (case tagval
               (#.x8664::fulltag-immheader-0
                (%svref *immheader-0-types* high4))
               (#.x8664::fulltag-immheader-1
                (%svref *immheader-1-types* high4))
               (#.x8664::fulltag-immheader-2
                (%svref *immheader-2-types* high4))
               (#.x8664::fulltag-nodeheader-0
                (%svref *nodeheader-0-types* high4))
               (#.x8664::fulltag-nodeheader-1
                (%svref *nodeheader-1-types* high4))
               (t 'bogus))))))

#+x8632-target
(defun valid-header-p (thing)
  (let* ((fulltag (fulltag thing)))
    (declare (fixnum fulltag))
    (case fulltag
      (#.x8632::fulltag-misc (valid-subtag-p (typecode thing)))
      ((#.x8632::fulltag-immheader #.x8632::fulltag-nodeheader) nil)
      (t t))))

#+x8664-target
(defun valid-header-p (thing)
  (let* ((fulltag (fulltag thing)))
    (declare (fixnum fulltag))
    (case fulltag
      ((#.x8664::fulltag-even-fixnum
        #.x8664::fulltag-odd-fixnum
        #.x8664::fulltag-imm-0
        #.x8664::fulltag-imm-1)
       t)
      (#.x8664::fulltag-function
       (= x8664::subtag-function (typecode (%function-to-function-vector thing))))
      (#.x8664::fulltag-symbol
       (= x8664::subtag-symbol (typecode (%symptr->symvector thing))))
      (#.x8664::fulltag-misc
       (valid-subtag-p (typecode thing)))
      ((#.x8664::fulltag-tra-0
        #.x8664::fulltag-tra-1)
       (let* ((disp (%return-address-offset thing)))
         (and disp
              (let* ((f (%return-address-function thing)))
                (and (typep f 'function) (valid-header-p f))))))
      (#.x8664::fulltag-cons t)
      (#.x8664::fulltag-nil (null thing))
      (t nil))))
             
#+x8632-target
(defun bogus-thing-p (x)
  (when x
    (or (not (valid-header-p x))
        (let ((tag (lisptag x))
	      (fulltag (fulltag x)))
          (unless (or (eql tag x8632::tag-fixnum)
                      (eql tag x8632::tag-imm)
                      (in-any-consing-area-p x)
		      (temporary-cons-p x)
		      (and (or (typep x 'function)
			       (typep x 'gvector))
			   (on-any-tsp-stack x))
		      (and (eql fulltag x8632::fulltag-tra)
			   (%return-address-offset x))
		      (and (typep x 'ivector)
			   (on-any-csp-stack x))
		      (%heap-ivector-p x))
	    t)))))

#+x8664-target
(defun bogus-thing-p (x)
  (when x
    (or (not (valid-header-p x))
        (let* ((tag (lisptag x)))
          (unless (or (eql tag x8664::tag-fixnum)
                      (eql tag x8664::tag-imm-0)
                      (eql tag x8664::tag-imm-1)
                      (in-any-consing-area-p x)
                      (temporary-cons-p x)
                      (and (or (typep x 'function)
                               (typep x 'gvector))
                           (on-any-tsp-stack x))
                      (and (eql tag x8664::tag-tra)
                           (eql 0 (%return-address-offset x)))
                      (and (typep x 'ivector)
                           (on-any-csp-stack x))
                      (%heap-ivector-p x))
            t)))))

