;;; -*- Mode: LISP; Syntax: Common-lisp; Package: (PCL Lisp 1000); Base: 10. -*-
;;;
;;; *************************************************************************
;;; Copyright (c) 1985, 1986, 1987 Xerox Corporation.  All rights reserved.
;;;
;;; Use and copying of this software and preparation of derivative works
;;; based upon this software are permitted.  Any distribution of this
;;; software or derivative works must comply with all applicable United
;;; States export control laws.
;;; 
;;; This software is made available AS IS, and Xerox Corporation makes no
;;; warranty about the software, its performance or its conformity to any
;;; specification.
;;; 
;;; Any person obtaining a copy of this software is requested to send their
;;; name and post office or electronic mail address to:
;;;   CommonLoops Coordinator
;;;   Xerox Artifical Intelligence Systems
;;;   2400 Hanover St.
;;;   Palo Alto, CA 94303
;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
;;;
;;; Suggestions, comments and requests for improvements are also welcome.
;;; *************************************************************************
;;;
;;; The version of low for Kyoto Common Lisp (KCL)
(in-package 'pcl)


;;;; low level stuff to hack compiled functions and compiled closures.
;;;
;;; The primary client for this is fsc-low, but since we make some use of
;;; it here (e.g. to implement set-function-name-1) it all appears here.
;;;

(eval-when (compile)

(defmacro define-cstruct-accessor (accessor structure-type field value-type)
  (let ((setf (intern (concatenate 'string "SET-" (string accessor))))
	(caccessor (format nil "pcl←get←~A←~A" structure-type field))
	(csetf     (format nil "pcl←set←~A←~A" structure-type field)))
    `(progn
       (CLines ,(format nil "~A ~A(~A)                ~%~
                             struct ~A *~A;           ~%~
                             { return ~A->~A; }       ~%~
                                                      ~%~
                             ~A ~A(~A, new)           ~%~
                             struct ~A *~A;           ~%~
                             ~A new;                  ~%~
                             { return ~A->~A = new; } ~%~
                            "
			value-type caccessor structure-type
			structure-type structure-type
			structure-type field

			value-type csetf structure-type
			structure-type structure-type
			value-type
			structure-type field))

       (defentry ,accessor (object) (object ,caccessor))
       (defentry ,setf (object object) (object ,csetf))
       (defsetf ,accessor ,setf)

       )))
)
;;; 
;;; struct cfun {                   /*  compiled function header  */
;;;         short   t, m;
;;;         object  cf←name;        /*  compiled function name  */
;;;         int     (*cf←self)();   /*  entry address  */
;;;         object  cf←data;        /*  data the function uses  */
;;;                                 /*  for GBC  */
;;;         char    *cf←start;      /*  start address of the code  */
;;;         int     cf←size;        /*  code size  */
;;; };
;;;
(define-cstruct-accessor cfun-name  "cfun" "cf←name"  "object")
(define-cstruct-accessor cfun-self  "cfun" "cf←self"  "int")
(define-cstruct-accessor cfun-data  "cfun" "cf←data"  "object")
(define-cstruct-accessor cfun-start "cfun" "cf←start" "char")
(define-cstruct-accessor cfun-size  "cfun" "cf←size"  "int")

(CLines
  "object pcl←cfunp (x)              "
  "object x;                         "
  "{if(x->c.t == (int) t←cfun)       "
  "  return (Ct);                    "
  "  else                            "
  "    return (Cnil);                "
  "  }                               "
  )

(defentry cfunp (object) (object pcl←cfunp))

;;; 
;;; struct cclosure {               /*  compiled closure header  */
;;;         short   t, m;
;;;         object  cc←name;        /*  compiled closure name  */
;;;         int     (*cc←self)();   /*  entry address  */
;;;         object  cc←env;         /*  environment  */
;;;         object  cc←data;        /*  data the closure uses  */
;;;                                 /*  for GBC  */
;;;         char    *cc←start;      /*  start address of the code  */
;;;         int     cc←size;        /*  code size  */
;;; };
;;; 
(define-cstruct-accessor cclosure-name "cclosure"  "cc←name"  "object")
(define-cstruct-accessor cclosure-self "cclosure"  "cc←self"  "int")
(define-cstruct-accessor cclosure-data "cclosure"  "cc←data"  "object")
(define-cstruct-accessor cclosure-start "cclosure" "cc←start" "char")
(define-cstruct-accessor cclosure-size "cclosure"  "cc←size"  "int")
(define-cstruct-accessor cclosure-env "cclosure"   "cc←env"   "object")


(CLines
  "object pcl←cclosurep (x)          "
  "object x;                         "
  "{if(x->c.t == (int) t←cclosure)   "
  "  return (Ct);                    "
  "  else                            "
  "   return (Cnil);                 "
  "  }                               "
  )

(defentry cclosurep (object) (object pcl←cclosurep))

  ;;   
;;;;;; Load Time Eval
  ;;
;;; 

;;; This doesn't work because it looks at a global variable to see if it is
;;; in the compiler rather than looking at the macroexpansion environment.
;;; 
;;; The result is that if in the process of compiling a file, we evaluate a
;;; form that has a call to load-time-eval, we will get faked into thinking
;;; that we are compiling that form.
;;;
;;; THIS NEEDS TO BE DONE RIGHT!!!
;;; 
;(defmacro load-time-eval (form)
;  ;; In KCL there is no compile-to-core case.  For things that we are 
;  ;; "compiling to core" we just expand the same way as if were are
;  ;; compiling a file since the form will be evaluated in just a little
;  ;; bit when gazonk.o is loaded.
;  (if (and (boundp 'compiler::*compiler-input*)  ;Hack to see of we are
;	   compiler::*compiler-input*)		  ;in the compiler!
;      `'(si:|#,| . ,form)
;      `(progn ,form)))

(defmacro memory-block-ref (block offset)
  `(svref (the simple-vector ,block) (the fixnum ,offset)))

  ;;   
;;;;;; Generating CACHE numbers
  ;;
;;; This needs more work to be sure it is going as fast as possible.
;;;   -  The calls to si:address should be open-coded.
;;;   -  The logand should be open coded.
;;;   

(defmacro symbol-cache-no (symbol mask)
  (if (and (constantp symbol)
	   (constantp mask))
      `(load-time-eval (logand (ash (si:address ,symbol) -2) ,mask))
      `(logand (ash (the fixnum (si:address ,symbol)) -2) ,mask)))

(defmacro object-cache-no (object mask)
  `(logand (the fixnum (si:address ,object)) ,mask))

  ;;   
;;;;;; printing-random-thing-internal
  ;;
(defun printing-random-thing-internal (thing stream)
  (format stream "~O" (si:address thing)))


(defun set-function-name-1 (fn new-name ignore)
  (cond ((cclosurep fn)
	 (setf (cclosure-name fn) new-name))
	((cfunp fn)
	 (setf (cfun-name fn) new-name))
	((and (listp fn)
	      (eq (car fn) 'lambda-block))
	 (setf (cadr fn) new-name))
	((and (listp fn)
	      (eq (car fn) 'lambda))
	 (setf (car fn) 'lambda-block
	       (cdr fn) (cons new-name (cdr fn)))))
  fn)