;;; -*- Mode:LISP; Package:LISP-INTERNALS; Base:10; Readtable:CL -*- ;;;; Storage Allocation ;;;; Low level storage allocation and storage conventions primitives (defmacro make-pointer (data-type pointer) `(hw:dpb-boxed ,data-type vinc:%%data-type ,pointer)) ;;; the header can be boxed and in the registers or md ;;; headers in dumped call stacks are ignored (defmacro make-header (header-type header-data) `(hw:dpb-boxed ,header-type vinc:%%data-type ,header-data)) (defmacro contents (pointer) `(progn (hw:vma-start-read-vma-boxed-md-boxed ,pointer) (hw:read-md))) (defmacro contents-offset (pointer offset) `(progn (hw:vma-start-read-vma-unboxed-md-boxed (hw:24+ ,offset ,pointer)) (hw:read-md))) ;;; @@@ Should this be a macro? <28-Oct-88 wkf> (defun store-contents (ptr value) (%store-contents ptr value)) ;;; @@@ Should this be a macro? <28-Oct-88 wkf> (defun store-contents-offset (ptr offset value) "This returns the value argument." (%store-contents-offset ptr offset value)) ;;;; Cons Mutators (defun set-car (list value) (if (vinc:consp list) (%set-car list value value) (error "Not a cons to set-car" list))) (defun rplaca (list value) (if (vinc:consp list) (%set-car list value list) (error "Not a cons to rplaca" list))) (defun set-cdr (list value) (if (vinc:consp list) (%set-cdr list value value) (error "Not a cons to set-cdr" list))) (defun rplacd (list value) (if (vinc:consp list) (%set-cdr list value list) (error "Not a cons to rplacd" list))) ;;;; CAR and CDR (eval-when (compile eval) (defun make-c.n.r (length &optional (suffix "") (guts 'list)) (if (= length 0) ; added package prefix - smh 30aug88 `(DEFUN ,(intern (format nil "C~aR" suffix) 'CONS) (list) ,guts) `(PROGN ,(make-c.n.r (1- length) (concatenate 'string "A" suffix) `(%CAR ,guts)) ,(make-c.n.r (1- length) (concatenate 'string "D" suffix) `(%CDR ,guts))))) (defmacro def-c...r (number) (let ((forms '())) (dotimes (i number) (push (make-c.n.r (1+ i)) forms)) `(PROGN ,@(nreverse forms)))) ) ;;; They're all in here: (def-c...r 4) (defsetf car set-car) (defsetf cdr set-cdr) ;;;; Structure Handles ;;; The structure handles record, for each cluster: ;;; - The number of boxed q's at the beginning of this cluster which ;;; are left over from structures which start before this cluster. ;;; - The offset in the cluster of the first header. ( if there is ;;; no header in this cluster) ;;; ;;; The structure handles allow us to scavenge the cluster and find headers ;;; of pointers into the cluster without looking at (ie paging in) the ;;; previous cluster. (defconstant %%structure-handle-first-header (byte 11. 0.)) (defconstant %%structure-handle-boxed-qs (byte 11. 11.)) (defconstant *no-first-header-code* #b11111111111) (defsubst write-structure-handles (cluster first-header left-over-boxed-qs) (hw:write-md-boxed (hw:dpb left-over-boxed-qs %%structure-handle-boxed-qs first-header)) (hw:vma-start-write-boxed (hw:24+ gr::*structure-handles* cluster))) (defsubst read-structure-handles (cluster thunk) (hw:vma-start-read (hw:24+ gr::*structure-handles* cluster)) (let ((stuff (hw:read-md))) (funcall thunk (hw:ldb stuff %%structure-handle-first-header 0) (hw:ldb stuff %%structure-handle-boxed-qs 0)))) (defsubst modify-structure-handles (cluster thunk) ;; This is dangerous because it assumes that the vma ;; remains unchanged for the computation of the new value. (read-structure-handles cluster #'(lambda (first-header boxed-qs) (funcall thunk first-header boxed-qs #'(lambda (new-first-header new-boxed-qs) (hw:md-start-write-boxed (hw:dpb new-boxed-qs %%structure-handle-boxed-qs new-first-header))))))) (defsubst structure-handle-first-header (cluster) (read-structure-handles cluster #'(lambda (first-header boxed-qs) boxed-qs first-header))) (defsubst structure-handle-boxed-qs (cluster) (read-structure-handles cluster #'(lambda (first-header boxed-qs) first-header boxed-qs))) (defsubst write-structure-handle-boxed-qs (cluster new-value) (modify-structure-handles cluster #'(lambda (first-header boxed-qs writer) first-header (funcall writer new-value boxed-qs)))) (defsubst write-structure-handle-first-header (cluster new-value) (modify-structure-handles cluster #'(lambda (first-header boxed-qs writer) boxed-qs (funcall writer first-header new-value)))) (defsetf structure-handle-first-header write-structure-handle-first-header) (defsetf structure-handle-boxed-qs write-structure-handle-boxed-qs) ;(defun foo (x) ; (structure-handle-first-header x)) (defconstant *structure-handles-quanta* (ceiling vinc:*number-of-virtual-clusters* vinc:*qs-in-quantum*)) (defun initialize-structure-handles () (let* ((structure-handles-area (make-area 0 (encode-region-bits region-bits:$$region-fixed region-bits:$$region-new-space region-bits:$$region-space-cons region-bits:$$region-read-write region-bits:$$scavenge-disabled region-bits:$$region-internal-memory 0.) 0)) (structure-handles-region (make-region-in-area structure-handles-area *structure-handles-quanta* 0 region-bits:$$region-fixed region-bits:$$region-new-space region-bits:$$region-space-cons region-bits:$$region-read-write region-bits:$$scavenge-disabled region-bits:$$region-internal-memory 0))) (setq gr::*structure-handles* (quantum->address structure-handles-region)) (make-area-fixed structure-handles-area) (dotimes (count vinc:*number-of-virtual-clusters*) (write-structure-handles count 0 0)))) ;;;; ENDP (defafun endp (l) (move nop a0 dt-right-list bw-32) (test br-zero) (branch end ()) (return gr:*NIL*) end (return gr:*T*)) ;;;; Cons (defafun cons (car cdr) ;; Turn off sequence breaks to avoid other processes consing after we ;; move the free pointer. ;; Check for a region in the cache. ;; Write the cdr at one beyond the free pointer. ;; Note: If you change this, you must also decide how to invalidate the cons cache. ;; Look in REGION-DATA for details. (alu r+1 gr::*allow-sequence-break* ignore gr::*allow-sequence-break* bw-24 boxed-right) try-again (move md a1 boxed-md) ; maybe pass cdr in md (alu r+1 vma-start-write ignore gr::*cons-cache-free* boxed-vma) ;; Bump the free pointer by 2. (alu r+2 gr::*cons-cache-free* ignore gr::*cons-cache-free* boxed) (nop) ;;Wait for possible asynchronous trap of above memory write. @@@ ||| 9/23/88 --wkf (nop) ;;Wait for possible asynchronous trap of above memory write. @@@ ||| 9/23/88 --wkf ;; Check to see if the cons cache was empty (zero). (alu r+1 nop ignore gr:*cons-cache-region* bw-24) ;; Scavenge, and check for region end at the end of each cluster. (alu-field field-pass nop gr::*cons-cache-free* gr::*cons-cache-free* ;; (byte 10. 0) #.(byte (byte-size vinc:%%offset-in-cluster) (- (byte-position vinc:%%offset-in-cluster))) br-zero) (branch cons-cache-empty (alu r-2 vma ignore gr::*cons-cache-free* br-zero boxed-vma)) ;;the address of the car (branch cluster-full (move md-start-write a0 boxed-md)) ;;write the car ;; Sequence breaks come back on, and we return the cons cell apropriately typed. (alu r-1 gr::*allow-sequence-break* ignore gr::*allow-sequence-break* boxed-right) (alu-field aligned-field-pass-left return gr::*dtp-cons* vma vinc:%%data-type ch-return next-pc-return boxed) cluster-full ;; Make the cons cell and call "cons new cluster" (nop) ;wait for the vma to load so it can be read by instruction two below! (alu xor nop gr::*cons-cache-limit* gr:*cons-cache-free* bw-24 unboxed) (alu-field aligned-field-pass-left a2 gr::*dtp-cons* vma vinc:%%data-type boxed br-not-zero) (branch exit-cluster-full ()) (open-call (cons-new-cluster 1) r0 (o0 gr::*cons-cache-area*)) exit-cluster-full ;; Sequence breaks come back on. (alu r-1 gr::*allow-sequence-break* ignore gr::*allow-sequence-break* bw-24 boxed-right) (return a2 boxed) cons-cache-empty (open-call (load-cons-cache 0) r0 nil) (unconditional-branch try-again ()) ) (defun load-cons-cache () (load-cons-cache-for-area gr:*cons-cache-area*)) ;;; Get a new cluster to cons in, check if we are at end ;;; of region and if so, get a new region and set up cons cache. ;;; Do some scavenging ;;; This should be called with sequence breaks off (defun cons-new-cluster (area) ; (unless (zerop gr::*scavenge-work-while-consing*) ; (gc:scavenge-while-consing)) (when (hw:32>= (hw:ldb gr::*cons-cache-free* vinc:%%pointer (hw:unboxed-constant 0)) (hw:ldb (region-data:region-end gr::*cons-cache-region*) vinc:%%pointer (hw:unboxed-constant 0))) (load-cons-cache-for-area gr::*cons-cache-area*))) (defun set-default-cons-area (area) (unless (= area gr::*cons-cache-area*) (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) (setq gr::*default-consing-area* area) (load-cons-cache-for-area area) (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*)))) (defun load-cons-cache-for-area (area) (get-active-region area region-bits:$$region-space-cons region-bits:$$region-new-space nil 2)) (defun cons-in-area (car cdr area) (if (= area gr::*cons-cache-area*) (cons car cdr) (progn (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) (let ((current-cache-area gr::*cons-cache-area*)) (load-cons-cache-for-area area) (prog1 (cons car cdr) (load-cons-cache-for-area current-cache-area) (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*))))))) ;;;; Structure Consing (defun allocate-structure (boxed-qs unboxed-qs data-type header) (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) (let ((qs-needed (hw:ldb (+ boxed-qs unboxed-qs) vinc:%%fixnum-field 0))) (labels ((try-again () (let ((new-free (hw:32+ (hw:ldb qs-needed vinc:%%fixnum-field (hw:unboxed-constant 0.)) gr::*structure-cons-cache-free*))) (if (or (region-data::structure-cons-cache-invalid?) (hw:32>= (hw:dpb-unboxed new-free vinc:%%pointer (hw:unboxed-constant 0)) (hw:dpb-unboxed gr::*structure-cons-cache-limit* vinc:%%pointer (hw:unboxed-constant 0)))) (progn (load-structure-cons-cache-for-area gr::*structure-cons-cache-area* qs-needed) (try-again)) (let ((pointer (make-pointer data-type gr::*structure-cons-cache-free*)) (end-cluster (cluster-number new-free))) ;; Store the header. (hw::write-md-unboxed header) (hw::vma-start-write-no-gc-trap-unboxed pointer) (let ((clusters-consed (if (not (hw:field= pointer new-free vinc:%%cluster-number)) ;; The cluster the object starts on is guaranteed to be set up correctly, ;; if we walk off the end of a cluster, we have to update structure ;; handles ;; accordingly (labels ((update-structure-handles (cluster-count cluster-scan boxed-qs) (cond ((= cluster-scan end-cluster) (write-structure-handles cluster-scan (hw:ldb new-free vinc:%%offset-in-cluster 0) boxed-qs) cluster-count) ((> boxed-qs vinc:*qs-in-cluster*) (write-structure-handles cluster-scan *no-first-header-code* vinc:*qs-in-cluster*) (update-structure-handles (1+ cluster-count) (1+ cluster-scan) (- boxed-qs vinc:*qs-in-cluster*))) (t (write-structure-handles cluster-scan *no-first-header-code* boxed-qs) (update-structure-handles (1+ cluster-count) (1+ cluster-scan) 0))))) (update-structure-handles 0 (cluster-number pointer) boxed-qs)) 0))) ;; Think about scavenging here ) (setq gr::*structure-cons-cache-free* new-free) (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*)) pointer))))) (try-again)))) (defun load-structure-cons-cache-for-area (area qs-needed) (get-active-region area region-bits:$$region-space-structure region-bits:$$region-new-space nil qs-needed)) (defun set-default-structure-cons-area (area) (unless (= area gr::*structure-cons-cache-area*) (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) (setq gr::*structure-cons-cache-area* area) (load-structure-cons-cache-for-area area 0) (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*)) )) (defun allocate-structure-in-area (boxed-qs unboxed-qs data-type header area) (if (= area gr::*structure-cons-cache-area*) (allocate-structure boxed-qs unboxed-qs data-type header) (progn (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) (let ((current-cache-area gr::*structure-cons-cache-area*)) (load-structure-cons-cache-for-area area (+ boxed-qs unboxed-qs)) (prog1 (allocate-structure boxed-qs unboxed-qs data-type header) (load-structure-cons-cache-for-area current-cache-area 0) (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*))))))) ;;; This is the top half of an illegal instruction (minus the stat bit) (defconstant code-header-instruction-high (hw:unboxed-constant #x7FFFFFFF)) ;;; Allocating Code space. (defun allocate-code-space (n-instructions associated-fef area) (setq gr::*allow-sequence-break* (1+ gr:*allow-sequence-break*)) (prog1 (map-fault:call-while-allowing-write-in-read-only #'(lambda () (let* ((qs-needed (ash (+ n-instructions 1) 1.)) region code-location) (do () (()) ;;;; This is gross - if the code crosses a 1/2 quantum boundary, then throw ;;;; this chunk away and try again. (setq region (get-active-region area region-bits:$$region-space-code region-bits:$$region-new-space nil qs-needed)) (setq code-location (make-pointer $$dtp-unboxed-locative (region-data:region-free-pointer region))) (let ((code-end (hw:24+ qs-needed code-location))) (when (hw:field= code-location (hw:32-1- code-end) (byte 13. 13.)) (setf (region-data:region-free-pointer region) code-end) (return)) (setf (region-data:region-free-pointer region) (hw:dpb 0. (byte 13. 0.) code-end)))) (setq gr:*allow-write-in-read-only* t) ;; This one is a pointer to the fef. (hw:write-md-boxed associated-fef) (hw:vma-start-write code-location) ;; Other word is magic marker word. (hw:write-md-unboxed code-header-instruction-high) (hw:vma-start-write-no-gc-trap-unboxed (hw:32-1+ code-location)) code-location))) ;; Think about scavenging here (setq gr::*allow-sequence-break* (1- gr:*allow-sequence-break*))))