\f
;;;; shared machinery for inline and out-of-line slot accessor functions
-;;; an alist mapping from raw slot type to the operator used to access
-;;; the raw slot
-;;;
-;;; FIXME: should be shared with other src/code/*defstruct*.lisp code
-;;; which refers to e.g. %RAW-REF-SINGLE, but as of sbcl-0.pre7.78
-;;; is only used by out-of-line versions
(eval-when (:compile-toplevel :load-toplevel :execute)
- (defvar *raw-type->rawref-fun-name*
- '(;; The compiler thinks that the raw data vector is a vector of
- ;; unsigned bytes, so if the slot we want to access actually *is*
- ;; an unsigned byte, it'll access the slot for us even if we don't
- ;; lie to it at all.
- (unsigned-byte . aref)
- ;; "A lie can travel halfway round the world while the truth is
- ;; putting on its shoes." -- Mark Twain
- (single-float . %raw-ref-single)
- (double-float . %raw-ref-double)
- #!+long-float (long-float . %raw-ref-long)
- (complex-single-float . %raw-ref-complex-single)
- (complex-double-float . %raw-ref-complex-double)
- #!+long-float (complex-long-float . %raw-ref-complex-long))))
+
+ ;; information about how a slot of a given DSD-RAW-TYPE is to be accessed
+ (defstruct raw-slot-data
+ ;; the raw slot type, or T for a non-raw slot
+ ;;
+ ;; (Raw slots are allocated in the raw slots array in a vector which
+ ;; the GC doesn't need to scavenge. Non-raw slots are in the
+ ;; ordinary place you'd expect, directly indexed off the instance
+ ;; pointer.)
+ (raw-type (missing-arg) :type (or symbol cons) :read-only t)
+ ;; What operator is used (on the raw data vector) to access a slot
+ ;; of this type?
+ (accessor-name (missing-arg) :type symbol :read-only t)
+ ;; How many words are each value of this type? (This is used to
+ ;; rescale the offset into the raw data vector.)
+ (n-words (missing-arg) :type (and index (integer 1)) :read-only t))
+
+ (defvar *raw-slot-data-list*
+ (list
+ ;; The compiler thinks that the raw data vector is a vector of
+ ;; word-sized unsigned bytes, so if the slot we want to access
+ ;; actually *is* an unsigned byte, it'll access the slot for us
+ ;; even if we don't lie to it at all, just let it use normal AREF.
+ (make-raw-slot-data :raw-type 'unsigned-byte
+ :accessor-name 'aref
+ :n-words 1)
+ ;; In the other cases, we lie to the compiler, making it use
+ ;; some low-level AREFish access in order to pun the hapless
+ ;; bits into some other-than-unsigned-byte meaning.
+ ;;
+ ;; "A lie can travel halfway round the world while the truth is
+ ;; putting on its shoes." -- Mark Twain
+ (make-raw-slot-data :raw-type 'single-float
+ :accessor-name '%raw-ref-single
+ :n-words 1)
+ (make-raw-slot-data :raw-type 'double-float
+ :accessor-name '%raw-ref-double
+ :n-words 2)
+ (make-raw-slot-data :raw-type 'complex-single-float
+ :accessor-name '%raw-ref-complex-single
+ :n-words 2)
+ (make-raw-slot-data :raw-type 'complex-double-float
+ :accessor-name '%raw-ref-complex-double
+ :n-words 4)
+ #!+long-float
+ (make-raw-slot-data :raw-type long-float
+ :accessor-name '%raw-ref-long
+ :n-words #!+x86 3 #!+sparc 4)
+ #!+long-float
+ (make-raw-slot-data :raw-type complex-long-float
+ :accessor-name '%raw-ref-complex-long
+ :n-words #!+x86 6 #!+sparc 8))))
\f
;;;; the legendary DEFSTRUCT macro itself (both CL:DEFSTRUCT and its
;;;; close personal friend SB!XC:DEFSTRUCT)
;;; RAW? is true if TYPE should be stored in a raw slot.
;;; RAW-TYPE is the raw slot type, or NIL if no raw slot.
;;; WORDS is the number of words in the raw slot, or NIL if no raw slot.
+;;;
+;;; FIXME: This should use the data in *RAW-SLOT-DATA-LIST*.
(defun structure-raw-slot-type-and-size (type)
(cond #+nil
(;; FIXME: For now we suppress raw slots, since there are various
(vector super)))))
;;; Do miscellaneous (LOAD EVAL) time actions for the structure
-;;; described by DD. Create the class & LAYOUT, checking for
+;;; described by DD. Create the class and LAYOUT, checking for
;;; incompatible redefinition. Define those functions which are
;;; sufficiently stereotyped that we can implement them as standard
;;; closures.
(setq layout (class-layout class))))
(setf (sb!xc:find-class (dd-name dd)) class)
- ;; It doesn't make sense to do these in the cross-compilation host.
+ ;; Various other operations only make sense on the target SBCL.
#-sb-xc-host
- (progn
- (remhash (dd-name dd) *typecheckfuns*)
- (%target-defstruct dd layout)
- (when (dd-doc dd)
- (setf (fdocumentation (dd-name dd) 'type)
- (dd-doc dd)))))
+ (%target-defstruct dd layout))
(values))
\f
(raw-type (dsd-raw-type dsd)))
(if (eq raw-type t) ; if not raw slot
`(,ref ,instance-name ,(dsd-index dsd))
- (let (;; the operator that we'll use to access one value in
- ;; the raw data vector
- (rawref (ecase raw-type
- ;; The compiler thinks that the raw data
- ;; vector is a vector of unsigned bytes, so if
- ;; the slot we want to access actually *is* an
- ;; unsigned byte, it'll access the slot for
- ;; us even if we don't lie to it at all.
- (unsigned-byte 'aref)
- ;; "A lie can travel halfway round the world while
- ;; the truth is putting on its shoes." -- Mark Twain
- (single-float '%raw-ref-single)
- (double-float '%raw-ref-double)
- #!+long-float (long-float '%raw-ref-long)
- (complex-single-float '%raw-ref-complex-single)
- (complex-double-float '%raw-ref-complex-double)
- #!+long-float (complex-long-float
- '%raw-ref-complex-long))))
- `(,rawref (,ref ,instance-name ,(dd-raw-index dd))
- ,(dsd-index dsd))))))
+ (let* ((raw-slot-data (find raw-type *raw-slot-data-list*
+ :key #'raw-slot-data-raw-type
+ :test #'equal))
+ (raw-slot-accessor (raw-slot-data-accessor-name raw-slot-data))
+ (raw-n-words (raw-slot-data-n-words raw-slot-data)))
+ (multiple-value-bind (scaled-dsd-index misalignment)
+ (floor (dsd-index dsd) raw-n-words)
+ (aver (zerop misalignment))
+ `(,raw-slot-accessor (,ref ,instance-name ,(dd-raw-index dd))
+ ,scaled-dsd-index))))))
;;; Return inline expansion designators (i.e. values suitable for
-;;; (INFO :FUNCTION :INLINE-EXPANSSION-DESIGNATOR ..)) for the reader
+;;; (INFO :FUNCTION :INLINE-EXPANSION-DESIGNATOR ..)) for the reader
;;; and writer functions of the slot described by DSD.
-(defun accessor-inline-expansion-designators (dd dsd)
- (values (lambda ()
- `(lambda (instance)
- (declare (type ,(dd-name dd) instance))
- (truly-the ,(dsd-type dsd)
- ,(%accessor-place-form dd dsd 'instance))))
- (lambda ()
- `(lambda (new-value instance)
- (declare (type ,(dsd-type dsd) new-value))
- (declare (type ,(dd-name dd) structure-object))
- (setf ,(%accessor-place-form dd dsd 'instance) new-value)))))
+(defun slot-accessor-inline-expansion-designators (dd dsd)
+ (let ((instance-type-decl `(declare (type ,(dd-name dd) instance)))
+ (accessor-place-form (%accessor-place-form dd dsd 'instance))
+ (dsd-type (dsd-type dsd)))
+ (values (lambda ()
+ `(lambda (instance)
+ ,instance-type-decl
+ (truly-the ,dsd-type ,accessor-place-form)))
+ (lambda ()
+ `(lambda (new-value instance)
+ (declare (type ,dsd-type new-value))
+ ,instance-type-decl
+ (setf ,accessor-place-form new-value))))))
+
+;;; Return a LAMBDA form which can be used to set a slot.
+(defun slot-setter-lambda-form (dd dsd)
+ (funcall (nth-value 1
+ (slot-accessor-inline-expansion-designators dd dsd))))
;;; core compile-time setup of any class with a LAYOUT, used even by
;;; !DEFSTRUCT-WITH-ALTERNATE-METACLASS weirdosities
(dsd-type (dsd-type dsd)))
(when accessor-name
(multiple-value-bind (reader-designator writer-designator)
- (accessor-inline-expansion-designators dd dsd)
+ (slot-accessor-inline-expansion-designators dd dsd)
(sb!xc:proclaim `(ftype (function (,dtype) ,dsd-type)
,accessor-name))
(setf (info :function :inline-expansion-designator accessor-name)
(res)))
\f
-;;;; slot accessors for raw slots
-
-;;; Return info about how to read/write a slot in the value stored in
-;;; OBJECT. This is also used by constructors (since we can't safely
-;;; use the accessor function, since some slots are read-only). If
-;;; supplied, DATA is a variable holding the raw-data vector.
-;;;
-;;; returned values:
-;;; 1. accessor function name (SETFable)
-;;; 2. index to pass to accessor.
-;;; 3. object form to pass to accessor
-(defun slot-accessor-form (defstruct slot object &optional data)
- (let ((rtype (dsd-raw-type slot)))
- (values
- (ecase rtype
- (single-float '%raw-ref-single)
- (double-float '%raw-ref-double)
- #!+long-float
- (long-float '%raw-ref-long)
- (complex-single-float '%raw-ref-complex-single)
- (complex-double-float '%raw-ref-complex-double)
- #!+long-float
- (complex-long-float '%raw-ref-complex-long)
- (unsigned-byte 'aref)
- ((t) '%instance-ref))
- (case rtype
- #!+long-float
- (complex-long-float
- (truncate (dsd-index slot) #!+x86 6 #!+sparc 8))
- #!+long-float
- (long-float
- (truncate (dsd-index slot) #!+x86 3 #!+sparc 4))
- (double-float
- (ash (dsd-index slot) -1))
- (complex-double-float
- (ash (dsd-index slot) -2))
- (complex-single-float
- (ash (dsd-index slot) -1))
- (t
- (dsd-index slot)))
- (cond
- ((eq rtype t) object)
- (data)
- (t
- `(truly-the (simple-array (unsigned-byte 32) (*))
- (%instance-ref ,object ,(dd-raw-index defstruct))))))))
-\f
;;; These functions are called to actually make a constructor after we
;;; have processed the arglist. The correct variant (according to the
;;; DD-TYPE) should be called. The function is defined with the
;;; various weird places, whereas STRUCTURE structures have
;;; a LAYOUT slot.
;;; * We really want to use LIST to make list structures, instead of
-;;; MAKE-LIST/(SETF ELT).
+;;; MAKE-LIST/(SETF ELT). (We can't in general use VECTOR in an
+;;; analogous way, since VECTOR makes a SIMPLE-VECTOR and vector-typed
+;;; structures can have arbitrary subtypes of VECTOR, not necessarily
+;;; SIMPLE-VECTOR.)
;;; * STRUCTURE structures can have raw slots that must also be
-;;; allocated and indirectly referenced. We use SLOT-ACCESSOR-FORM
-;;; to compute how to set the slots, which deals with raw slots.
+;;; allocated and indirectly referenced.
(defun create-vector-constructor (dd cons-name arglist vars types values)
(let ((temp (gensym))
(etype (dd-element-type dd)))
vars types))
(list ,@vals))))
(defun create-structure-constructor (dd cons-name arglist vars types values)
- (let* ((temp (gensym))
- (raw-index (dd-raw-index dd))
- (n-raw-data (when raw-index (gensym))))
+ (let* ((instance (gensym "INSTANCE"))
+ (raw-index (dd-raw-index dd)))
`(defun ,cons-name ,arglist
- (declare ,@(mapcar #'(lambda (var type) `(type ,type ,var))
+ (declare ,@(mapcar (lambda (var type) `(type ,type ,var))
vars types))
- (let ((,temp (truly-the ,(dd-name dd)
- (%make-instance ,(dd-length dd))))
- ,@(when n-raw-data
- `((,n-raw-data
- (make-array ,(dd-raw-length dd)
- :element-type '(unsigned-byte 32))))))
- (setf (%instance-layout ,temp)
- (%delayed-get-compiler-layout ,(dd-name dd)))
- ,@(when n-raw-data
- `((setf (%instance-ref ,temp ,raw-index) ,n-raw-data)))
+ (let ((,instance (truly-the ,(dd-name dd)
+ (%make-instance-with-layout
+ (%delayed-get-compiler-layout ,(dd-name dd))))))
+ (declare (optimize (safety 0))) ; Suppress redundant slot type checks.
+ ,@(when raw-index
+ `((setf (%instance-ref ,instance ,raw-index)
+ (make-array ,(dd-raw-length dd)
+ :element-type '(unsigned-byte 32)))))
,@(mapcar (lambda (dsd value)
- (multiple-value-bind (accessor index data)
- (slot-accessor-form dd dsd temp n-raw-data)
- `(setf (,accessor ,data ,index) ,value)))
+ ;; (Note that we can't in general use the
+ ;; ordinary named slot setter function here
+ ;; because the slot might be :READ-ONLY, so we
+ ;; whip up new LAMBDA representations of slot
+ ;; setters for the occasion.)
+ `(,(slot-setter-lambda-form dd dsd) ,value ,instance))
(dd-slots dd)
values)
- ,temp))))
+ ,instance))))
;;; Create a default (non-BOA) keyword constructor.
(defun create-keyword-constructor (defstruct creator)