;;; -*- Mode:LISP; Package:SIM; Fonts:(CPTFONT HL12I); Base:10; Readtable:ZL -*-


(defreg *active-cons-cache-area*              0 0)
(defreg *active-cons-cache-region*            0 1)
(defreg *active-cons-cache-region-origin*     0 2)
(defreg *active-cons-cache-free-pointer*      0 3)
(defreg *active-cons-cache-free-limit*        0 4)
(defreg *active-cons-cache-allocation-status* 0 5)
(defreg *list-allocation-threshold*           0 6)
(defreg *default-cons-area*                   0 7)
;; This is 4x page-size, so scavenger work is at least 4x cons work.
(defreg *scavenge-work-while-consing*         0 8) ;2000



(defun test-setup ()
  (setq *scavenge-work-while-consing* 0)
  (setq *list-allocation-threshold* 16.)
  (setq *default-cons-area* ksi:working-storage-area)
  (setq *active-cons-cache-area* 0)
  (setq *active-cons-cache-allocation-status* 0)
  (setq *active-cons-cache-free-pointer* 0)
  (setq *active-cons-cache-free-limit* 10000.))

(defun l3 (a b c)
  (cons a (cons b (cons c nil))))


(DEFKFUN L3 (A B C)
  TAG::P_7
  (TAIL-OPEN)
  (KOPEN)
  (MOVE O0 A2 CH-OPEN)
  (KCALL KSI:CONS '2 O1 (O1 'NIL))
  TAG::C_11
  (KCALL KSI:CONS '2 O1 (O0 A1))
  TAG::C_14
  (TAIL-CALL KSI:CONS '2 (O0 A0)))



(defun KSI:CONS (car cdr)
  (let ((loc (allocate-list-storage 2 *default-cons-area*)))
    (%loc-store-car loc car)
    (%loc-store-cdr loc cdr)
    (%k-make-pointer #.dtp-list loc)
    ))


(DEFKFUN KSI::CONS (CAR CDR)
  TAG::P_8
     (MOVE O0 '2 CH-OPEN)
     (KCALL ALLOCATE-LIST-STORAGE '2 A2 (O1 (%REGISTER *DEFAULT-CONS-AREA* 0 7)))
  TAG::C_19
     (MOVE MD A0)
     (MOVE VMA-START-WRITE A2)
     (MOVE MD A1)
     (ALU ALU-OR VMA-START-WRITE A2 '1)
     (KDPB RETURN '14 A2 %%PTR-DATA-TYPE CH-RETURN))





(defun allocate-list-storage (length area)
  (cond ((not (= area *active-cons-cache-area*))
	 (allocate-list-storage-uncached length area))
	((> (setq *active-cons-cache-allocation-status*
		  (+ length *active-cons-cache-allocation-status*))
	    *list-allocation-threshold*)
	 (allocate-list-storage-cached-list-header length area))
	(t
	 (let ((temp (%loc-+ *active-cons-cache-free-pointer* length)))
	   (if (%loc-> temp *active-cons-cache-free-limit*)
	       (allocate-list-storage-uncached length area)
	     (let ((ptr *active-cons-cache-free-pointer*))   ;prog1
	       (setq *active-cons-cache-free-pointer* temp)
	       ptr))))))


(DEFKFUN ALLOCATE-LIST-STORAGE (LENGTH AREA)
  TAG::P_10
      (ALU L-R GARBAGE A1 (%REGISTER *ACTIVE-CONS-CACHE-AREA* 0 0))
      (TEST BR-NOT-EQUAL)
      (BRANCH TAG::C_13)
  TAG::C_16
      (ALU L+R
           (%REGISTER *ACTIVE-CONS-CACHE-ALLOCATION-STATUS* 0 5)
           A0
           (%REGISTER *ACTIVE-CONS-CACHE-ALLOCATION-STATUS* 0 5))
      (MOVE A2 (%REGISTER *ACTIVE-CONS-CACHE-ALLOCATION-STATUS* 0 5))
      (ALU L-R GARBAGE A2 (%REGISTER *LIST-ALLOCATION-THRESHOLD* 0 6))
      (TEST BR-NOT-GREATER-THAN)
      (BRANCH TAG::C_21)
  TAG::C_19
      (MOVE O0 A0 CH-TAIL-OPEN)
      (TAIL-CALL ALLOCATE-LIST-STORAGE-CACHED-LIST-HEADER '2 (O1 A1))
  TAG::C_21
      (ALU L+R A3 (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) A0)
      (ALU L-R GARBAGE A3 (%REGISTER *ACTIVE-CONS-CACHE-FREE-LIMIT* 0 4))
      (TEST BR-NOT-GREATER-THAN)
      (BRANCH TAG::C_27)
  TAG::C_25
      (MOVE O0 A0 CH-TAIL-OPEN)
      (TAIL-CALL ALLOCATE-LIST-STORAGE-UNCACHED '2 (O1 A1))
  TAG::C_27
      (MOVE A4 (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3))
      (MOVE (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) A3)
      (MOVE RETURN A4 CH-RETURN)
  TAG::C_13
      (MOVE O0 A0 CH-TAIL-OPEN)
      (TAIL-CALL ALLOCATE-LIST-STORAGE-UNCACHED '2 (O1 A1)))




;;; Cons cache hit, but we need to insert a list header
;;; (so that find-structure-header doesn't have to search
;;; too far).  This path is a bit slower, but
;;; not nearly as bad as the uncached case.
(defun allocate-list-storage-cached-list-header (length area)
  (let ((new-free-pointer (%loc-+ *active-cons-cache-free-pointer* (+ length 2))))
    (if (%loc-> new-free-pointer *active-cons-cache-free-limit*)
	(allocate-list-storage-uncached length area)
      (progn (%loc-store-car *active-cons-cache-free-pointer*
			     (%k-make-pointer #.dtp-header #.%header-type-list))
	     ;; can't just store one word header now
	     ;; since conses are always on even addresses
	     (%loc-store-cdr *active-cons-cache-free-pointer*
			     nil)
	     (let ((ptr (%loc-+ *active-cons-cache-free-pointer* 2)))
	       (setq *active-cons-cache-free-pointer* new-free-pointer)
	       (setq *active-cons-cache-allocation-status* 0)
	       ptr)))))
;      ;; the ucode does it like this? contorted but safer??
;      (setq start-of-list (%loc-+ *active-cons-cache-free-pointer* 1)
;	    *active-cons-cache-free-pointer* new-free-pointer
;	    *active-cons-cache-allocation-status* 0)
;      (%loc-store (%loc--1 start-of-list)
;		  (%k-make-pointer #.dtp-header #.%header-type-list)))))


(DEFKFUN ALLOCATE-LIST-STORAGE-CACHED-LIST-HEADER (LENGTH AREA)
  TAG::P_10
     (ALU L+R A2 A0 '2)
     (ALU L+R A3 (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) A2)
     (ALU L-R GARBAGE A3 (%REGISTER *ACTIVE-CONS-CACHE-FREE-LIMIT* 0 4))
     (TEST BR-NOT-GREATER-THAN)
     (BRANCH TAG::C_16)
  TAG::C_14
     (MOVE O0 A0 CH-TAIL-OPEN)
     (TAIL-CALL ALLOCATE-LIST-STORAGE-UNCACHED '2 (O1 A1))
  TAG::C_16
     (KDPB A4 '7 '3 %%PTR-DATA-TYPE)
     (MOVE MD A4)
     (MOVE VMA-START-WRITE (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3))
     (MOVE MD 'NIL)
     (ALU ALU-OR VMA-START-WRITE (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) '1)
     (ALU L+R A5 (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) '2)
     (MOVE (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) A3)
     (MOVE (%REGISTER *ACTIVE-CONS-CACHE-ALLOCATION-STATUS* 0 5) '0)
     (MOVE RETURN A5 CH-RETURN))






1;allocate-list-storage-uncached
;        ((m-a) m-b)*				1;legislate boxed-size  total-size.
;     ;; invalidate cache before we might trap out (just a good idea, probably not necessary).
;
;
;        (call-xct-next decode-area-specification)
;       (call-not-equal m-minus-one a-active-cons-cache-area invalidate-active-cons-cache)
;
;;;; this does the same thing.
;;      (call-not-equal m-minus-one a-active-cons-cache-area invalidate-active-cons-cache)
;;      (call decode-area-specification)  ;;returns area spec in m-s
;
;        (call-not-equal-xct-next m-zero a-scavenge-work-while-consing scavenge-while-consing)
;       ((a-scavenge-work) a-scavenge-work-while-consing)
;        (call-xct-next get-active-region)*	1;return allocation-status in q-r
;       ((vma-start-read) add m-s a-v-area-region-list)
;     ;; insert list-header if last object was structure, or if over threshold.
;        (call-greater-than q-r a-list-allocation-threshold insert-list-header)
;     ;; now m-t has address of object, m-b has total size, and m-a has boxed size.
;        (call-xct-next touch-pages-in-new-object)
;       ((a-active-cons-cache-allocation-status) add m-b a-active-cons-cache-allocation-status)
;        (jump update-structure-handles-for-object)*


(defun allocate-list-storage-uncached (length area)
  "The basic, slow path, for list storage allocation"
  (unless (null *active-cons-cache-area*) (invalidate-active-cons-cache))
  (setq area (decode-area-specification area))
  (unless (zerop *scavange-work-while-consing*)
    (scavenge-while-consing *scavenge-work-while-consing*))
  ;; insert list-header if last object was structure, or if over threshold.
  (if (> (get-active-region length area) *list-allocation-threshold*)
      (insert-list-header))
  (setq *active-cons-cache-allocation-status*
	(+ length *active-cons-cache-allocation-status*))
  (touch-pages-in-new-object)
  (update-structure-handles-for-object))




1;invalidate-active-cons-cache
;*	1(popj-equal a-active-cons-cache-region m-minus-one)
;        ((m-3) a-active-cons-cache-region)
;        ((vma) add m-3 a-v-region-free-pointer)
;        ((md) a-active-cons-cache-free-pointer)
;        ((md-start-write) output-selector-mask-25 sub md a-active-cons-cache-region-origin)
;        (check-page-write-unboxed)
;        ((a-active-cons-cache-area) m-minus-one)
;        ((a-active-cons-cache-region) m-minus-one)*	1       ;Scavenger depends on this.
;        ((vma) add m-3 a-v-region-allocation-status)
;        (popj-after-next
;          (md-start-write) a-active-cons-cache-allocation-status)
;       (check-page-write-unboxed)*

(defun invalidate-active-cons-cache ()
  (unless (null *active-cons-cache-region*)
    (let ((region *active-cons-cache-region*))
      (%loc-store (%loc-+ *v-region-free-pointer* region)
		  ;; this is (- loc loc) not (- loc fix) ???
		  (%loc-- *active-cons-cache-free-pointer* *active-cons-cache-region-origin*))
      (setq *active-cons-cache-area* nil)
      (setq *active-cons-cache-region* nil)
      (%loc-store (%loc-+ *v-region-allocation-status* region)
		  *active-cons-cache-allocation-status*))))
    
    
1;insert-list-header
;    ;; Insert a list-header to indicate a transition from structure-storage to list-storage.
;        ((a-active-cons-cache-free-pointer) m+a+1 m-zero a-active-cons-cache-free-pointer)
;        ((a-active-cons-cache-allocation-status) m-zero)
;        ((m-t) add m-t (a-constant 1))
;        ((md) (a-constant (plus (byte-value q-cdr-code cdr-error)
;*			1        (byte-value q-data-type dtp-header)
;*			1        (byte-value q-header-type %header-type-list))))
;        (popj-after-next
;          (vma-start-write) sub m-t (a-constant 1))
;       (check-page-write-unboxed)*

(defun insert-list-header ()
  ;; ucode updates free pointer first, safer?
  (%loc-store-car *active-cons-cache-free-pointer*
		  (%k-make-pointer #.dtp-header #.%header-type-list))
  ;; can't just store one word header now
  ;; since conses are always on even addresses
  (%loc-store-cdr *active-cons-cache-free-pointer*
		  nil)
  (setq *active-cons-cache-free-pointer* (%loc-+ *active-cons-cache-free-pointer 2)
	*active-cons-cache-allocation-status* 0)
  *active-cons-cache-free-pointer*)
    
       


(defun allocate-structure-storage (length area)
  (cond ((not (= area *active-cons-cache-area*))
	 (allocate-structure-storage-uncached length area))
	(t
	 (let ((temp (%loc-+ *active-cons-cache-free-pointer* length)))
	   (if (%loc-> temp *active-cons-cache-free-limit*)
	       (allocate-structure-storage-uncached length area)
	     ;; Set allocation-status to > threshold
	     ;; to force list-header insertion next list-structure cons.
	     (progn (setq *active-cons-cache-allocation-status* (1+ *list-allocation-threshold*))
		    (let ((ptr *active-cons-cache-free-pointer*))   ;prog1
		      (setq *active-cons-cache-free-pointer* temp)
		      ptr)))))))


(DEFKFUN ALLOCATE-STRUCTURE-STORAGE (LENGTH AREA)
  TAG::P_10
     (ALU L-R GARBAGE A1 (%REGISTER *ACTIVE-CONS-CACHE-AREA* 0 0))
     (TEST BR-NOT-EQUAL)
     (BRANCH TAG::C_13)
  TAG::C_16
     (ALU L+R A2 (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) A0)
     (ALU L-R GARBAGE A2 (%REGISTER *ACTIVE-CONS-CACHE-FREE-LIMIT* 0 4))
     (TEST BR-NOT-GREATER-THAN)
     (BRANCH TAG::C_22)
  TAG::C_20
     (MOVE O0 A0 CH-TAIL-OPEN)
     (TAIL-CALL ALLOCATE-STRUCTURE-STORAGE-UNCACHED '2 (O1 A1))
  TAG::C_22
     (ALU L+R+1
          (%REGISTER *ACTIVE-CONS-CACHE-ALLOCATION-STATUS* 0 5)
          (%REGISTER *LIST-ALLOCATION-THRESHOLD* 0 6)
       '0)
     (MOVE A3 (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3))
     (MOVE (%REGISTER *ACTIVE-CONS-CACHE-FREE-POINTER* 0 3) A2)
     (MOVE RETURN A3 CH-RETURN)
  TAG::C_13
     (MOVE O0 A0 CH-TAIL-OPEN)
     (TAIL-CALL ALLOCATE-STRUCTURE-STORAGE-UNCACHED '2 (O1 A1)))






1;allocate-structure-storage-uncached
;     ;; Invalidate cache before we might trap out (just a good idea, probably not necessary).

;;;; Can this hope to win?
;;;; Yes!  And it does what you would expect it to do.
;      *     (1call-xct-next decode-area-specification)
;     *     (1call-not-equal m-minus-one a-active-cons-cache-area invalidate-active-cons-cache)

;;;; This is what the above code equals.
;;  (call-not-equal m-minus-one a-active-cons-cache-area invalidate-active-cons-cache)
;;  (call decode-area-specification)

;        (call-not-equal-xct-next m-zero a-scavenge-work-while-consing scavenge-while-consing)
;       ((a-scavenge-work) a-scavenge-work-while-consing)
;        (call-xct-next get-active-region)
;       ((vma-start-read) add m-s a-v-area-region-list)
;     ;; Now M-T has address of object, M-B has total size, and M-A has boxed size.
;        (call-xct-next touch-pages-in-new-object)
;       ((a-active-cons-cache-allocation-status) dpb m-minus-one q-pointer a-zero)
;        (jump update-structure-handles-for-object)*

    
1;;;; Decode area specification in M-S.  Return boxed fixnum in M-S.
;decode-area-specification
;*	1(declare (args a-s) (values a-s))
;        (call-data-type-equal m-s (a-constant (byte-value q-data-type dtp-symbol)) decode-area-symbol)
;        (call-less-than m-s (a-constant (byte-value q-data-type dtp-fix)) trap)
;     (error-table argtyp area m-s nil)
;        (call-greater-than m-s (a-constant (plus (byte-value q-data-type dtp-fix) 377)) trap)
;     (error-table argtyp area m-s nil)
;        (popj)
;decode-area-symbol
;*	1(declare (args a-s) (values a-s))
;*	1((vma-start-read) output-selector-mask-25 add m-s (a-constant 1))*	1;Value cell.
;*	1(check-page-read)
;*	1(popj-after-next dispatch transport md)
;       ((m-s) q-typed-pointer md)*

(defun decode-area-specification (area-spec)
  "Take an area-specification and return the area number as a fixnum"
  (if (symbolp area-spec)
      (setq area-spec (symbol-value area-spec)))
  ;; ucode did pointer compare and caught non fixnums
  (if (or (< area-spec 0)		       
	  (> area-spec #.maximum-area-number))
      (error "~a is not a valid area number." area-spec)
  area-spec))




1;;; Dispatch table for GET-ACTIVE-REGION, below.  Dispatches on region space type to find
;;; an active region appropriate to cons in.
(locality d-mem)
(start-dispatch 4 0)
d-verify-region-type*
	1(p-bit n-bit trap)*			1;0 FREE*
	1(n-bit get-active-region-loop)*		1;1 OLD (try next region)*
	1(p-bit r-bit)*				1;2 NEW*
	1(p-bit n-bit trap)*			1;3*
	1(p-bit n-bit trap)*			1;4*
	1(p-bit n-bit trap)*			1;5*
	1(p-bit n-bit trap)*			1;6*
	1(p-bit n-bit trap)*			1;7*
	1(p-bit n-bit trap)*			1;10*
	1(p-bit r-bit)*				1;11 STATIC*
	1(p-bit n-bit trap)*			1;12 FIXED*
	1(p-bit r-bit)*				1;13 EXTRA-PDL*
	1(n-bit get-active-region-loop)*		1;14 COPY (try next region)*
	1(n-bit get-active-region-loop)*		1;15 MOBY-FIXED (try next region)*
	1(p-bit r-bit)*				1;16 MOBY-NEW  try this one.
(repeat 1 (p-bit n-bit trap))*			1;  code 15 up are MOBY.
(end-dispatch)
(locality i-mem)

;;; Subroutine of allocate-storage.  Call with area number (fixnum) in M-S, total number
;;; of words needed in M-B (untyped).  Finds a NEW, STATIC, or EXTRA-PDL region in area
;;; that has enough room to hold the new object, or allocates a new region for that area.
;;; Currently this fails if the object is larger than the region size of the area.
;;; Return region-allocation-status of region found in q-r.
get-active-region-loop
        ((vma-start-read) add m-k a-v-region-list-thread)
get-active-region
        (check-page-read)
     ;No transport, region list is not in oldspace (ever) (I think). -jrm
        ((m-k) q-pointer md)
     ;; If at end of region list, allocate another region, or reset extra-pdl and retry.
        (call-if-bit-set boxed-sign-bit m-k allocate-active-region)
        ((vma-start-read) add m-k a-v-region-bits)
        (check-page-read)
     ;; Check region-space-type.  If not suitable, jump to get-active-region-loop.
        (dispatch (lisp-byte %%region-space-type) md d-verify-region-type)
     (error-table cons-in-inappropriate-region)
     ;; Fall through for legitimate active region types (new, static, or extra-pdl).*
	1((vma-start-read) add m-k a-v-region-origin)*
	1(check-page-read)*
	1((a-active-cons-cache-region-origin) q-pointer md a-zero)
        ((vma-start-read) add m-k a-v-region-length)
        (check-page-read)
        ((m-3) output-selector-mask-25 add md a-active-cons-cache-region-origin)
        ((vma-start-read) add m-k a-v-region-free-pointer)
        (check-page-read)
        ((m-t) output-selector-mask-25 add md a-active-cons-cache-region-origin)
     ;; Compare region-free-pointer against region-length to see if there is enough room
     ;; for the object.  Note that we require that there be (1+ M-B) words, because we might
     ;; have to insert a list-header later on.
        ((a-active-cons-cache-free-pointer q-r) add m-t a-b)
        (jump-greater-or-equal q-r a-3 get-active-region-loop)
     ;; Set up the free limit to word 0 on the page following the free-pointer.  However,
     ;; If the free-pointer is at word 0 of a page, set the limit to that page, so the
     ;; structure-handles get set up correctly next time around.
        ((m-tem) add q-r (a-constant 377))
        ((a-active-cons-cache-free-limit) dpb m-zero q-page-index a-tem)
        ((vma-start-read) add m-k a-v-region-allocation-status)
        (check-page-read)
     ;; Note: GET-ACTIVE-REGION must return the allocation-status in the Q register.
        ((a-active-cons-cache-allocation-status q-r) md)
        (popj-after-next
          (a-active-cons-cache-region) m-k)
       ((a-active-cons-cache-area) m-s)*


;;; temporary, really turns into a dispatch instruction
;;; similiar to dispatch but takes addresses
(defmacro kdispatch (field value &body clauses)
  `(case (ldb ,field ,value)
     ,@(mapcar #'(lambda (clause)
		   `(,(car clause) (go ,(cadr clause))))
	       clauses)))
		   
;;; Subroutine of allocate-storage.  Call with area number (fixnum) in M-S, total number
;;; of words needed in M-B (untyped).  Finds a NEW, STATIC, or EXTRA-PDL region in area
;;; that has enough room to hold the new object, or allocates a new region for that area.
;;; Currently this fails if the object is larger than the region size of the area.
;;; Return region-allocation-status of region found in q-r.

(defun get-active-region (size area-number)
  (let ((region-num (%loc-read (%loc-+ *v-area-region-list* area-number))))   ;actually this could be an array
    ;; no transport, region list is never in oldspace (jrm)
    (tagbody
	loop
	   ;; If at end of region list, allocate another region, or reset extra-pdl and retry.
	   (if (boxed-sign-bit??? region-num)
	       (setq region-num (allocate-active-region size area-number)))
	   ;; Check region-space-type.  If not suitable, jump to get-active-region-loop.
	   (kdispatch %%region-space-type (%loc-read (%loc-+ *v-region-bits* region-num))   ;could be an array
	      (0 bad-region)				;free, trap
	      (1 get-active-region-loop)		;old, try next region
	      (2 ok)					;new
	      (11 ok)					;static
	      (12 bad-region)				;fixed, trap
	      (13 ok)					;extra-pdl
	      (14 get-active-region-loop)		;copy, try next region
	      (15 get-active-region-loop)		;moby, try next region
	      (16 ok)					;moby-new
	      (otherwise bad-region))
	bad-region
	   (error "Cons in inappropriate region ~a" region-num)
	get-active-region-loop
	   (setq region-num (%loc-read (%loc-+ *v-region-list-thread* region-num)))
	   (go loop)		 
	ok ;;legitimate active region types (new, static, or extra-pdl).
	   (setq *active-cons-cache-region-origin*  ;type?
		 (%loc-read (%loc-+ *v-region-origin* region-num)))
	   (let ((region-end (%loc-+ *active-cons-cache-region-origin*
			      (%loc-read (%loc-+ *v-region-length* region-num))))
	  (region-free (%loc-+ *active-cons-cache-region-origin*
			       (%loc-read (%loc-+ *v-region-free-pointer* region-num)))))
      (setq *active-cons-cache-free-pointer* (%loc-+ size region-free))
      ;; Compare region-free-pointer against region-length to see if there is enough room
      ;; for the object.  Note that we require that there be (1+ M-B) words, because we might
      ;; have to insert a list-header later on.
      (if (%loc-< region-end *active-cons-cache-free-pointer*)
	  (go get-active-region-loop)))
    ;; Set up the free limit to word 0 on the page following the free-pointer.  However,
    ;; If the free-pointer is at word 0 of a page, set the limit to that page, so the
    ;; structure-handles get set up correctly next time around.
    (setq *active-cons-cache-free-limit*
	  (dpb 0 %%ptr-page-index (%loc+ *active-cons-cache-free-limit* #.page-size)))
    (setq *active-cons-cache-region* region-num
	  *active-cons-cache-area* area-number
	  *active-cons-cache-allocation-status*
	  (%loc-read (%loc-+ *v-region-allocation-status* region-num)))))




;1allocate-active-region*
;	1(jump-equal m-s (a-constant extra-pdl-area-number) extra-pdl-overflow)*
;1        (call get-area-region-bits)*		1;return in M-4*
;1     ;; Volatility for active regions comes from area-region-bits.*
;1        ((m-e) (lisp-byte %%region-volatility) m-4)*
;	1((m-tem) (lisp-byte %%region-space-type) m-4)*
;	1(jump-greater-or-equal m-tem (a-constant (eval %region-space-moby-fixed))*
;			1       allocate-moby-region)*

(defun allocate-active-region (size area)
  (if (= area #.ksi:extra-pdl-area)
      (extra-pdl-overflow)
    (let ((region-bits (get-area-region-bits area)))
      (ldb %%region-volatility region-bits)	;what does it do with this?
      (allocate-region size area))))

       
      
;1allocate-region*
;	1((vma-start-read) add m-s a-v-area-region-size)*
;	1(check-page-read)*
;	1((m-3) q-pointer md)*			1;Normal amount to allocate.*
;	1(jump-greater-than m-3 a-b rcons1)*
;	1((m-3) add m-b (a-constant 1))*		1;M-3 amount we want to allocate.*
;1rcons1*	1(call make-region)*		1;Allocate a region of that size (to M-K).*
;1     ;; Update REGION-AREA-MAP to know about new region.*
;1        ((md) dpb m-s q-pointer a-zero)*
;1        ((vma-start-write) add m-k a-v-region-area-map)*
;1        (check-page-write)*
;1     ;; Insert new region at front of AREA-REGION-LIST.*
;	1((vma-start-read) add m-s a-v-area-region-list)*
;	1(check-page-read)*
;	1((m-3) md)*				1;This becomes the next region.*
;	1((md-start-write) dpb m-k q-pointer a-3)*
;	1(check-page-write)*
;	1((md) m-3)*
;	1(popj-after-next*
;1          (vma-start-write) add m-k a-v-region-list-thread)*
;1       (check-page-write)*

(defun allocate-region (size area)
  (let ((region-size (%loc-read (%loc-+ *v-area-region-size* area))))
    (unless (> region-size size)
      (setq region-size (1+ size)))
    ;;Allocate a region of that size
    (let ((region (make-region region-size)))
      ;; Update REGION-AREA-MAP to know about new region.
      (%loc-store (%loc-+ *v-region-area-map* region)
		  area)
      ;; Insert new region at front of AREA-REGION-LIST.
      ;;vma doesn't need to be written twice...
      (let ((old-first-region (%loc-read (%loc-+ *v-area-region-list* area))))	
	(%loc-store (%loc-+ *v-area-region-list* area)
		    region)
	(%loc-store (%loc-+ *v-region-list-thread* region)
		    old-first-region))
      region)))
		    

1    *
;;; A convenient subroutine for %MAKE-STRUCTURE and %MAKE-ARRAY.
;;; Allocates and initializes an appropriate structure.
(defun allocate-block (area total-size boxed-size)
  (initialize-storage   
    (allocate-structure-storage total-size area)
    total-size
    boxed-size
    nil))


(DEFKFUN ALLOCATE-BLOCK (AREA TOTAL-SIZE BOXED-SIZE)
  TAG::P_7
     (TAIL-OPEN)
     (MOVE O0 A1 CH-OPEN)
     (KCALL ALLOCATE-STRUCTURE-STORAGE '2 O0 (O1 A0))
  TAG::C_10
     (MOVE O1 A1)
     (MOVE O2 A2)
     (TAIL-CALL INITIALIZE-STORAGE '4 (O3 'NIL)))

  
1;;;; Subroutine of make-structure for initializing both boxed and unboxed storage.
;;;; Given an address in M-T, the number of boxed words (untagged) in M-A, and the
;;;; total number of words (untagged) in M-B, initialize all the boxed qs to the value
;;;; popped off the stack, with cdr codes of cdr-next (last one gets cdr-nil), and all
;;;; the unboxed words to zero.

;initialize-storage
;*	1((md) ldb pdl-pop q-all-but-cdr-code (a-constant (byte-value q-cdr-code cdr-next)))
;*	1((m-3) setm m-a)*			1;Number of boxed words to initialize.
;        ((m-4) sub m-b a-3)*			1;Total number of words.
;*	1((vma) sub m-t (a-constant 1))
;*	1(jump-less-or-equal m-3 (a-constant 1) initialize-boxed-storage-1)
;initialize-boxed-storage-0
;*	1((vma-start-write) add vma (a-constant 1))
;*	1(check-page-write)
;        (gc-write-test)*				1       ;850726
;*	1(jump-greater-than-xct-next m-3 (a-constant 2) initialize-boxed-storage-0)
;       ((m-3) sub m-3 (a-constant 1))
;initialize-boxed-storage-1
;*	1((md) q-all-but-cdr-code md (a-constant (byte-value q-cdr-code cdr-nil)))
;*	1((vma-start-write) add vma (a-constant 1))
;*	1(check-page-write)
;        (gc-write-test)*				1       ;850726
;initialize-unboxed-storage
;        ((md) setz)
;initialize-unboxed-storage-0
;        (popj-less-or-equal m-4 a-zero)
;        ((vma-start-write) add vma (a-constant 1))
;        (check-page-write-unboxed)
;        (jump-xct-next initialize-unboxed-storage-0)
;       ((m-4) sub m-4 (a-constant 1))*




;;; Subroutine of make-structure for initializing both boxed and unboxed storage.
;;; Given a block, the number of boxed words, and the
;;; total number of words, initialize all the boxed qs to the value, (&cdr codes!?)
;;; and all the unboxed words to zero.
(defun initialize-storage (block total-words boxed-words value)
  (let ((unboxed-words (- total-words boxed-words)))
    (tagbody
	(setq K:VMA (%loc-1 block))
	(setq K:MD value)
     initialize-boxed-storage
	(%vma-write-next)
	(decf boxed-words)
	(if (> boxed-words 0)
	    (go initialize-boxed-storage))
  ;; initialize-unboxed-storage
	(setq K:MD 0)
     initialize-unboxed-storage
	(if (<= unboxed-words 0)
	    (return-from initialize-storage block))
	(%vma-write-next)			;check write unboxed
	(decf unboxed-words)
	(go initialize-unboxed-storage))))


(DEFKFUN INITIALIZE-STORAGE (BLOCK TOTAL-WORDS BOXED-WORDS VALUE)
  TAG::P_15
     (ALU L-R A4 A1 A2)
     (ALU L+R-1 (%REGISTER VMA NIL NIL) A0 '0)
     (MOVE (%REGISTER MD NIL NIL) A3)
  TAG::INITIALIZE-BOXED-STORAGE_47
     (ALU L+R+1 VMA-START-WRITE VMA '0)
     (ALU L-R A2 A2 '1)
     (ALU L-R GARBAGE A2 '0)
     (TEST BR-NOT-GREATER-THAN)
     (BRANCH TAG::C_59)
  TAG::C_56
     (JUMP TAG::INITIALIZE-BOXED-STORAGE_47)
  TAG::C_59
     (MOVE (%REGISTER MD NIL NIL) '0)
  TAG::INITIALIZE-UNBOXED-STORAGE_23
     (ALU L-R GARBAGE A4 '0)
     (TEST BR-NOT-LESS-THAN-OR-EQUAL)
     (BRANCH TAG::C_29)
  TAG::C_26
     (MOVE RETURN A0 CH-RETURN)
  TAG::C_29
     (ALU L+R+1 VMA-START-WRITE VMA '0)
     (ALU L-R A4 A4 '1)
     (JUMP TAG::INITIALIZE-UNBOXED-STORAGE_23))









1;List-of-nils
;        ((pdl-push) a-v-nil)
;list-of-things
;        ((m-a) m-b)*				1       ;Boxed-size  Total-size.
;        (call-return allocate-list-storage initialize-storage)*




  
1;;;; (%make-structure pointer-data-type header-data-type header second-word area total boxed)

;        (misc-inst-entry %make-structure)
;x-make-structure
;        (call allocate-block)
;        ((vma) add m-t (a-constant 1))
;        ((md-start-write) c-pdl-buffer-pointer-pop)
;        (check-page-write)
;*	1(gc-write-test-volatility)*	1;OK since data is boxed.
;        ((m-tem1) c-pdl-buffer-pointer-pop)
;        ((md) dpb c-pdl-buffer-pointer-pop q-all-but-pointer a-tem1)
;        ((vma-start-write m-t) dpb c-pdl-buffer-pointer-pop q-all-but-pointer a-t)
;        (check-page-write)
;*	1(gc-write-test-volatility)*	1;OK since data is boxed.
;        (popj)*


(defun %make-structure (pointer-data-type header-data-type
			header second-word
			area total boxed)
  (let ((block (allocate-block area total boxed)))
    (%loc-store (%loc+1 block) second-word)
    (%loc-store (%k-make-pointer pointer-data-type block)
		(%k-make-pointer header-data-type header))))



1;;;; (%make-array header-word index-length leader-length area total-size boxed-size)

;        (misc-inst-entry %make-array)
;x-make-array
;        (call allocate-block)
;        ((vma m-t) q-pointer m-t (a-constant (byte-value q-data-type dtp-array-pointer)))
;        ((m-e) output-selector-mask-25 add m-t a-b)    ;Last storage location.
;        ((m-c) q-pointer pdl-pop)*	1        ;Leader length.
;        ((m-b) q-pointer pdl-pop)*	1        ;Index length.
;        (call-if-bit-set-xct-next (lisp-byte %%array-leader-bit) c-pdl-buffer-pointer
;*	1    make-array-leader)
;       ((m-d) dpb pdl-pop q-pointer (a-constant (byte-value q-data-type dtp-array-header)))
;        ((md-start-write) m-d)*			1;Store header.
;        (check-page-write-no-sequence-break)*	1;storage conventions would not be consistant...
;        ((m-tem) ldb (lisp-byte %%array-type-field) m-d)
;        (call-equal m-tem (a-constant (eval (ldb %%array-type-field art-complex)))
;            initialize-complex-array)
;;;; ***** NEVER NEVER NEVER LEAVE ARRAY HEADERS IN ACCUMULATORS *******
;;;; It took me a week to find this bug! -JRM
;        (popj-if-bit-clear-xct-next (lisp-byte %%array-long-length-flag) m-d)
;       ((m-d) a-v-nil)

;        ((vma) add m-t (a-constant 1))
;        ((md-start-write) dpb m-b q-pointer (a-constant (byte-value q-data-type dtp-fix)))
;        (check-page-write)
;        (popj)*


(defun %make-array (header-word index-length leader-length area total-size boxed-size)
  (let ((array (%k-make-pointer #.dtp-array-pointer
				(allocate-block area total-size boxed-size))))
    (%loc-store array (%k-make-pointer #.dtp-array-header header-word))
    (if (bit-test #.%%array-leader-bit header-word)
	(make-array-leader))
;    (if (= (ldb #.%%array-type-field header-word)
;	   #.(ldb %%array-type-field art-complex))
;	(initialize-complex-array))
    (when (bit-test #.%%array-long-length-flag header-word)
      (%loc-store (%loc+1 array) index-length))
    array))


(DEFKFUN %MAKE-ARRAY (HEADER-WORD INDEX-LENGTH LEADER-LENGTH AREA TOTAL-SIZE BOXED-SIZE)
  TAG::P_12
     (MOVE O0 A3 CH-OPEN)
     (MOVE O1 A4)
     (KCALL ALLOCATE-BLOCK '3 A6 (O2 A5))
  TAG::C_64
     (KDPB A7 '17 A6 %%PTR-DATA-TYPE)
     (KDPB A8 '18 A0 %%PTR-DATA-TYPE)
     (MOVE MD A8)
     (MOVE VMA-START-WRITE A7)
     (ALU ALU-AND A9 '1089 A0)
     (ALU L-R GARBAGE A9 '0)
     (TEST BR-NOT-EQUAL)
     (BRANCH TAG::C_20)
  TAG::C_23
     (JUMP TAG::B_59)
  TAG::C_20
     (OPEN-CALL MAKE-ARRAY-LEADER '0 IGNORE NIL)
  TAG::C_118
  TAG::B_59
     (ALU ALU-AND A9 '705 A0)
     (ALU L-R GARBAGE A9 '0)
     (TEST BR-NOT-EQUAL)
     (BRANCH TAG::C_40)
  TAG::C_45
     (MOVE RETURN A7 CH-RETURN)
  TAG::C_40
     (ALU L+R+1 A10 A7 '0)
     (MOVE MD A1)
     (MOVE VMA-START-WRITE A10)
     (MOVE RETURN A7 CH-RETURN))




(defvar art-q-1d-header (%LOGDPB 1 system:%%ARRAY-NUMBER-DIMENSIONS
				 (%LOGDPB art-q system:%%ARRAY-TYPE-FIELD 0)))




      
1make-array-leader
     ;; Build and store array leader header.  VMA points to leader header word.  VMA and M-T
     ;; have dtp-array-pointer throughout this code.
        ((md-start-write) add m-c*
	1    (a-constant (plus (byte-value q-data-type dtp-header)*
			1      (byte-value %%header-type-field %header-type-array-leader)*
			1      2)))
        (check-page-write-no-sequence-break)
     ;; Word before array header, gets leader length.
        ((vma m-t) m+a+1 m-t a-c)
        ((md-start-write) dpb m-c q-pointer (a-constant (byte-value q-data-type dtp-fix)))
        (check-page-write)
     ;; Leave VMA, M-T pointing to array header.
        (popj-after-next
          (vma m-t) add m-t (a-constant 1))
       (no-op)*
    
  
  
