Changeset 434


Ignore:
Timestamp:
Jan 30, 2004, 12:09:13 PM (21 years ago)
Author:
Gary Byers
Message:

Lots of changes: foreign slot definitions have a :FOREIGN-TYPE;
initarg is used to recognize them. Foreign direct slot offset is
(slightly encoded, for bitfields) relative slot offset, can be set by
parsing ivars of predefined classes or from :FOREIGN-TYPE when setting
(CLASS-DIRECT-SLOTS). Effective-slot location set from class's own
direct slot or from superclass direct slot.
The foreign "init.." method is called as part of ALLOCATE-INSTANCE,
not (again) in SHARED-INITIALIZE.
ENSURE-CLASS-USING-CLASS tries to do what we mean, not what we say.
Hook into the guts of NSObjectDeallocate to note when an instance is
deallocated (and remove its lisp slots-vector); still needs work.
Note that saving images with foreign classes in them still doesn't
work.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ccl/examples/objc-clos.lisp

    r379 r434  
    1919;;;  - MAP-OBJC-CLASS needs to INITIALIZE-INSTANCE and FINALIZE-INHERITANCE
    2020;;;    for predefined classes
    21 ;;;  - OBJC-FOREIGN-ARG-TYPE in BRIDGE.LISP needs to handle BITFIELDs,
    22 ;;;    ARRAYs and UNIONs
    2321;;;  - Need to fully handle init keywords and ObjC init messages
    24 ;;;  - Need to add getter and setter functions for more foriegn slot types
     22;;;  - Need to add getter and setter functions for more foreign slot types
    2523;;;  - Canonicalization and retention for ObjC objects
    2624;;;  - Support redef of CLOS parts, but not changes in ObjC parts
     
    4947(package-force-export "NS")
    5048
    51 
    5249;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    5350;;;;                                 Testing                                ;;;;
    5451;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     52
     53;;; Enable some debugging output.
     54(defparameter *objc-clos-debug* nil)
    5555
    5656;;; Until foreign slot definition objects automatically show up where they're
     
    160160
    161161(defclass objc:objc-class-object (foreign-class objc:objc-object)
    162     ((foreign :initform t)
    163      (peer :initform nil)))
     162    ((foreign :initform nil :initarg :foreign)
     163     (peer :initform nil :initarg :peer)))
    164164
    165165(defclass objc:objc-metaclass (objc:objc-class-object)
     
    170170(defclass objc:objc-class (objc:objc-class-object)
    171171    ())
     172
     173(setq *objc-class-class* (find-class 'objc:objc-class))
    172174
    173175(defmethod objc-metaclass-p ((c class))
     
    198200
    199201
    200 
    201 (defun initialize-objc-class-slots (class class-name wrapper &optional foreign)
    202 ;  (format t "~&initialize-objc-class-slots ~s (#x~x)" class-name (%ptr-to-int class)) 
    203 ; (force-output)
    204   (let* ((super (pref class :objc_class.super_class))
    205          (super-id (unless (%null-ptr-p super) (objc-class-id super)))
    206          (super-slots (if super-id
    207                         (id->objc-class-slots-vector super-id)
    208                         (instance.slots (find-class 'objc:objc-object))))
    209          (super-cpl (%slot-ref super-slots %class.cpl)))
    210     (gvector :slot-vector
    211              class
    212              nil                        ;direct-methods
    213              nil                        ;prototype
    214              class-name
    215              (cons class super-cpl)     ;cpl
    216              wrapper
    217              (list (slot-vector.instance super-slots)) ;local-supers
    218              nil ;subclasses
    219              nil ;dependents
    220              (make-class-ctype class) ;ctype
    221              nil ;direct-slots
    222              nil ;slots
    223              t ;kernel-p
    224              nil ;local-default-initargs
    225              nil ;default-initargs
    226              nil ;alist
    227              foreign
    228              nil
    229              )))
    230 
    231 (defun initialize-objc-metaclass-slots (class class-name wrapper
    232                                         &optional foreign peer)
    233 ;  (format t "~&initialize-objc-metaclass-slots ~s" class-name)
    234 ;  (force-output)
    235   (let* ((super (pref class :objc_class.super_class))
    236          (super-id (unless (%null-ptr-p super) (objc-metaclass-id super)))
    237          (super-slots (if super-id
    238                         (id->objc-metaclass-slots-vector super-id)
    239                         (instance.slots (find-class 'objc:objc-class))))
    240          (super-cpl (%slot-ref super-slots %class.cpl))
    241          (eslotds (class-slots (find-class 'objc:objc-class))))
    242     (setup-slot-lookup wrapper eslotds)
    243     (gvector :slot-vector
    244              class
    245              nil                        ;direct-methods
    246              nil                        ;prototype
    247              class-name
    248              (cons class super-cpl)     ;cpl
    249              wrapper
    250              (list (slot-vector.instance super-slots)) ;local-supers
    251              nil ;subclasses
    252              nil ;dependents
    253              (make-class-ctype class) ;ctype
    254              nil ;direct-slots
    255              eslotds ;slots
    256              t ;kernel-p
    257              nil ;local-default-initargs
    258              nil ;default-initargs
    259              nil ;alist
    260              foreign
    261              peer
    262              )))
     202(defun make-objc-class-object-slots-vector (class meta)
     203  (let* ((n (1+ (length (extract-instance-effective-slotds meta))))
     204         (slots (allocate-typed-vector :slot-vector n (%slot-unbound-marker))))
     205    (setf (slot-vector.instance slots) class)
     206    slots))
     207
     208(defun make-objc-metaclass-slots-vector (metaclass)
     209  (make-objc-class-object-slots-vector metaclass *objc-metaclass-class*))
     210
     211(defun make-objc-class-slots-vector (class)
     212  (make-objc-class-object-slots-vector class *objc-class-class*))
     213
    263214
    264215
     
    289240;;; Metaclasses for foreign slots
    290241
     242(defconstant objc-bitfield-offset-mask (ash 1 28) "When set in a foreign
     243DIRECT slot definition's offset, indicates that the low 27 bits are a bit
     244offset into the slots of the relevant class.")
     245
     246(defconstant objc-bitfield-offset-bit-offset (byte 22 6) "bit offset of
     247most significant bitfield bit in word; corresponding byte offset will
     248be word-aligned")
     249
     250(defconstant objc-bitfield-offset-byte-offset (byte 22 0) "byte offset
     251of field, relative to start of class's own slots")
     252
    291253(defclass foreign-direct-slot-definition (direct-slot-definition)
    292   ((foreign :initarg :foreign))
    293   (:default-initargs :type :id))
     254  ((foreign-type :initarg :foreign-type :initform :id :accessor foreign-slot-definition-foreign-type)
     255   (offset :initarg :offset
     256           :initform nil
     257           :accessor foreign-direct-slot-definition-offset
     258           :documentation "A byte- (or, if certain high bits are set, bit-)
     259offset, relative to the start of the instance's slots.  The corresponding
     260effective slot definition's offset is a product of this value and the
     261instance_size of its ObjC superclass."))
     262  (:default-initargs :foreign-type :id))
    294263
    295264(defclass foreign-effective-slot-definition (effective-slot-definition)
    296   ((getter :type function :accessor foreign-slot-definition-getter)
     265  ((foreign-type :initarg :foreign-type :initform :id :accessor foreign-slot-definition-foreign-type)
     266   (getter :type function :accessor foreign-slot-definition-getter)
    297267   (setter :type function :accessor foreign-slot-definition-setter)))
    298268
    299269
    300 ;;; Use the foreign slot metaclasses if the slot has a :FOREIGN attribute
    301 ;;  of T
     270;;; Use the foreign slot metaclasses if the slot has a :FOREIGN-TYPE attribute
     271;; 
    302272
    303273(defmethod direct-slot-definition-class ((class objc:objc-class-object)
    304274                                         &rest initargs)
    305   (if (getf initargs :foreign)
    306       (find-class 'foreign-direct-slot-definition)
     275  (if (getf initargs :foreign-type)
     276    (find-class 'foreign-direct-slot-definition)
    307277    (find-class 'standard-direct-slot-definition)))
    308278
    309279(defmethod effective-slot-definition-class ((class objc:objc-class-object)
    310280                                            &rest initargs)
    311   (if (getf initargs :foreign)
    312       (find-class 'foreign-effective-slot-definition)
     281  (if (getf initargs :foreign-type)
     282    (find-class 'foreign-effective-slot-definition)
    313283    (find-class 'standard-effective-slot-definition)))
     284
     285;;; A little structure used to drive the state-driven ivar-parsing mechanism.
     286(defstruct
     287    (ivar-parse-state (:constructor %make-ivar-parse-state (class-origin)))
     288  (class-origin 0 :type fixnum)
     289  (last-byte-offset-seen nil :type (or null fixnum))
     290  (bitfield-offset nil :type (or null fixnum)))
     291
     292(defun make-ivar-parse-state (class)
     293  (%make-ivar-parse-state (superclass-instance-size class)))
    314294
    315295
     
    323303        (loop with ns-package = (find-package "NS")
    324304              with n = (pref ivars :objc_ivar_list.ivar_count)
     305              with state = (make-ivar-parse-state c)
    325306              for i from 1 to n
    326307              for ivar = (pref ivars :objc_ivar_list.ivar_list)
     
    330311              when (eql (schar name 0) #\_)
    331312                do (unexport sym ns-package)
    332               do (format t "~S: ~S~%" name (pref ivar :objc_ivar.ivar_offset))
     313              ;do (format t "~S: ~S~%" name (pref ivar :objc_ivar.ivar_offset))
    333314              collect
    334               (make-direct-slot-definition
     315              (make-direct-slot-definition-from-ivar
     316               state
     317               (pref ivar :objc_ivar.ivar_offset)
     318               (with-string-from-cstring
     319                          (s (pref ivar :objc_ivar.ivar_type))
     320                        (objc-foreign-type-for-ivar s))
    335321               c
    336322               (list
    337323                :name sym
    338324                :allocation :instance
    339                 :foreign t
    340                 :class (find-class 'foreign-effective-slot-definition)
    341                 :type (objc-foreign-arg-type
    342                        (%get-cstring (pref ivar :objc_ivar.ivar_type)))
    343 ;               :offset (pref ivar :objc_ivar.ivar_offset)
    344 )))))))
     325                :class c )))))))
     326
     327(defun make-direct-slot-definition-from-ivar (state
     328                                              ivar-offset
     329                                              slot-type
     330                                              class
     331                                              initargs)
     332  (let* ((byte-offset (- ivar-offset (ivar-parse-state-class-origin state)))
     333         (offset byte-offset))
     334    (if (or (eq slot-type 'bit)
     335            (and (consp slot-type) (eq (car slot-type) 'bitfield)))
     336      (let* ((width (if (eq slot-type 'bit) 1 (cadr slot-type)))
     337             (bit-offset
     338              (if (eql offset (ivar-parse-state-last-byte-offset-seen state))
     339                (ivar-parse-state-bitfield-offset state)
     340                (or (ivar-parse-state-bitfield-offset state) 0))))
     341        (setf (ivar-parse-state-last-byte-offset-seen state) offset
     342              (ivar-parse-state-bitfield-offset state) (+ bit-offset width))
     343        (setq offset (logior objc-bitfield-offset-mask
     344                             (dpb bit-offset
     345                                  objc-bitfield-offset-bit-offset
     346                                  offset)))))
     347    (let* ((slot
     348            (make-direct-slot-definition
     349             class
     350             `(:foreign-type ,slot-type :offset ,offset ,@initargs))))
     351      slot)))
     352           
     353
     354(defun set-objc-foreign-direct-slot-offsets (dslotds)
     355  (let* ((byte-offset 0))
     356    (dolist (d dslotds)
     357      (let* ((type (foreign-slot-definition-foreign-type d))
     358             (ftype (parse-foreign-type type))
     359             (type-alignment (progn (ensure-foreign-type-bits ftype)
     360                                    (foreign-type-alignment ftype))))
     361        (if (= type-alignment 1)
     362          (break "Bitfields not handled yet: ~s" type))
     363        (setq byte-offset
     364              (align-offset byte-offset (ceiling type-alignment 8)))
     365        (setf (foreign-direct-slot-definition-offset d) byte-offset)
    345366       
     367        (setq byte-offset
     368              (+ byte-offset
     369                 (ceiling (foreign-type-bits ftype) 8)))))))
     370       
     371
     372;;; When an ObjC class is created by the user, the OFFSET fields in
     373;;; its foreign direct slot definitions are generally not set.  We
     374;;; can compute them fairly easily, but this is stateful (a slot's
     375;;; offset may depend on its predecessor's offset.)  Intercept the
     376;;; attempt to set the classes direct slots and ensure that all
     377;;; of those slots have proper offsets.
     378;;; (In any case that I can think of, we should either find that
     379;;; all foreign direct slots have non-null offsets or that none
     380;;; do.  If any don't, recompute all of them.
     381(defmethod (setf class-direct-slots) :before (dslotds (class objc::objc-class))
     382  (let* ((foreign-dslotds
     383          (loop for d in dslotds
     384                when (typep d 'foreign-direct-slot-definition)
     385                collect d)))
     386    (unless
     387      (dolist (d foreign-dslotds t)
     388        (if (not (foreign-direct-slot-definition-offset d))
     389          (return nil)))
     390      (set-objc-foreign-direct-slot-offsets foreign-dslotds))))
     391                                               
     392
     393(defun lisp-defined-slot-name-to-objc-slot-name (lisp-name)
     394  (lisp-to-objc-message (list lisp-name)))
     395
     396;;; This is only going to be called on a class created by the user;
     397;;; the byte part of each foreign direct slotd's offset field should
     398;;; already have been set.
     399(defun %make-objc-ivars (class)
     400  (let* ((start-offset (superclass-instance-size class))
     401         (foreign-dslotds (loop for s in (class-direct-slots class)
     402                                when (typep s 'foreign-direct-slot-definition)
     403                                collect s)))
     404    (if (null foreign-dslotds)
     405      (values (%null-ptr) start-offset)
     406      (let* ((n (length foreign-dslotds))
     407             (offset start-offset)
     408             (ivars (malloc (+ 4 (* n (%foreign-type-or-record-size
     409                                       :objc_ivar :bytes))))))
     410      (setf (pref ivars :objc_ivar_list.ivar_count) n)
     411      (do* ((l foreign-dslotds (cdr l))
     412            (dslotd (car l) (car l))
     413            (ivar (pref ivars :objc_ivar_list.ivar_list)
     414                  (%inc-ptr ivar (%foreign-type-or-record-size
     415                                 :objc_ivar :bytes))))
     416           ((null l) (values ivars (align-offset offset 4)))
     417        (let* ((string (lisp-defined-slot-name-to-objc-slot-name (slot-definition-name dslotd)))
     418               (type (parse-foreign-type (foreign-slot-definition-foreign-type dslotd)))
     419               (encoding (encode-objc-type type)))
     420          (setq offset
     421            (+ start-offset
     422                   (ldb objc-bitfield-offset-byte-offset
     423                        (foreign-direct-slot-definition-offset dslotd))))
     424          (setf (pref ivar :objc_ivar.ivar_name) (make-cstring string)
     425                (pref ivar :objc_ivar.ivar_type) (make-cstring encoding)
     426                (pref ivar :objc_ivar.ivar_offset) offset)
     427          (setq offset (+ offset (ceiling (foreign-type-bits type) 8)))))))))
    346428
    347429(defun %objc-ivar-offset-in-class (name c)
     
    369451      (or (locate-objc-slot name c)
    370452          (error "No ObjC instance variable named ~S in ~S" name c)))))
    371  
     453
     454;;; Maintain the class wrapper of an ObjC class or metaclass.
     455
     456(defmethod (setf class-own-wrapper) :after (wrapper (class objc::objc-metaclass))
     457  (setf (id->objc-metaclass-wrapper (objc-metaclass-id class)) wrapper))
     458
     459(defmethod (setf class-own-wrapper) :after (wrapper (class objc::objc-class))
     460  (setf (id->objc-class-wrapper (objc-class-id class)) wrapper))
    372461
    373462;;; Return the getter and setter functions for a foreign slot
    374463;;; NOTE: Should be changed to use FOREIGN-TYPE-TO-REPRESENTATION-TYPE
    375464
    376 (defclass unhandled-foreign-slot ()
    377     ((ftype :initarg :ftype :accessor unhandled-foreign-slot-ftype)))
    378 
    379 (defmethod print-object ((ufs unhandled-foreign-slot) stream)
    380   (print-unreadable-object (ufs stream :type t :identity t)
    381     (format stream "for foreign type ~s" (unhandled-foreign-slot-ftype ufs))))
    382465
    383466(defun compute-foreign-slot-accessors (eslotd)
    384   (let ((ftype (%slot-definition-type eslotd)))
    385     (flet ((unhandled-foreign-slot-type (ptr &optional offset)
    386              (declare (ignore ptr offset))
    387              (make-instance 'unhandled-foreign-slot :ftype ftype)))
    388       (case ftype
    389         (:unsigned-byte (values #'%get-unsigned-byte #'%set-byte))
    390         (:signed-byte (values #'%get-signed-byte #'%set-byte))
    391         (:unsigned-word (values #'%get-unsigned-word #'%set-word))
    392         (:signed-word (values #'%get-signed-word #'%set-word))
    393         (:unsigned-fullword (values #'%get-unsigned-long #'%set-long))
    394         (:signed-fullword (values #'%get-signed-long #'%set-long))
    395         (:unsigned-longlong
    396          (values #'%%get-unsigned-longlong #'%%set-unsigned-longlong))
    397         (:signed-longlong
    398          (values #'%%get-signed-longlong #'%%set-signed-longlong))
    399         (:single-float (values #'%get-single-float #'%set-single-float))
    400         (:double-float (values #'%get-double-float #'%set-double-float))
    401         ((:id :address) (values #'%get-ptr #'%set-ptr))
    402         (t
    403          (cond
    404           ((and (consp ftype) (eq (first ftype) :*))
    405            (values #'%get-ptr #'%set-ptr))
    406           (t (values #'unhandled-foreign-slot-type
    407                      #'unhandled-foreign-slot-type))))))))
    408 
    409 
    410 ;;; Augment SLOT-CLASS's COMPUTE-EFFECTIVE-SLOT-DEFINITION with an :AROUND
    411 ;;; method for OBJC-CLASSes that sets up foreign slot info
     467  (let* ((ftypespec (foreign-slot-definition-foreign-type eslotd))
     468         (ftype (parse-foreign-type ftypespec)))
     469    (etypecase ftype
     470      (foreign-integer-type
     471       (let* ((bits (foreign-integer-type-bits ftype))
     472              (align (foreign-integer-type-alignment ftype))
     473              (signed (foreign-integer-type-signed ftype)))
     474         (if (= bits align)
     475           (ecase bits
     476             (1 (values #'%get-bit #'%set-bit))
     477             (8 (values (if signed #'%get-signed-byte #'%get-unsigned-byte)
     478                        #'%set-byte))
     479             (16 (values (if signed #'%get-signed-word #'%get-unsigned-word)
     480                         #'%set-word))
     481             (32 (values (if signed #'%get-signed-long #'%get-unsigned-long)
     482                         #'%set-long))
     483             (64 (if signed
     484                   (values #'%%get-signed-longlong #'%%set-signed-longlong)
     485                   (values #'%%get-unsigned-longlong #'%%set-unsigned-longlong))))
     486             (values #'(lambda (ptr offset)
     487                          (%get-bitfield ptr offset bits))
     488                      #'(lambda (ptr offset new)
     489                          (setf (%get-bitfield ptr offset bits) new))))))
     490      (foreign-double-float-type
     491       (values #'%get-double-float #'%set-double-float))
     492      (foreign-single-float-type
     493       (values #'%get-single-float #'%set-single-float))
     494      (foreign-pointer-type
     495       (values #'%get-ptr #'%set-ptr))
     496      (foreign-mem-block-type
     497       (let* ((nbytes (%foreign-type-or-record-size ftype :bytes)))
     498         (values #'%inc-ptr #'(lambda (pointer offset new)
     499                                (setf (%composite-pointer-ref
     500                                       nbytes
     501                                       pointer
     502                                       offset)
     503                                      new))))))))
     504   
     505
     506
     507;;; Shadow SLOT-CLASS's COMPUTE-EFFECTIVE-SLOT-DEFINITION with a
     508;;; method for OBJC-CLASSes that sets up foreign slot info.
    412509
    413510(defmethod compute-effective-slot-definition :around ((class objc:objc-class-object)
    414511                                                      name
    415512                                                      direct-slots)
    416   (let* ((first (first direct-slots))
    417          (eslotd (call-next-method)))
    418     (when (typep first 'foreign-direct-slot-definition)
    419       (setq eslotd
    420             (make-effective-slot-definition
    421              class
    422              :name name
    423              :allocation (%slot-definition-allocation eslotd)
    424              :foreign t
    425              :documentation (%slot-definition-documentation eslotd)
    426              :class (%slot-definition-class first)
    427              :initargs (%slot-definition-initargs eslotd)
    428              :initfunction (%slot-definition-initfunction eslotd)
    429              :initform (%slot-definition-initform eslotd)
    430              :type (%slot-definition-type eslotd)))
     513  (let* ((first (first direct-slots)))
     514    (if (not (typep first 'foreign-direct-slot-definition))
     515      (call-next-method)
     516      (let* ((initer (dolist (s direct-slots)
     517                       (when (%slot-definition-initfunction s)
     518                         (return s))))
     519             (documentor (dolist (s direct-slots)
     520                           (when (%slot-definition-documentation s)
     521                             (return s))))
     522             (initargs (let* ((initargs nil))
     523                         (dolist (dslot direct-slots initargs)
     524                           (dolist (dslot-arg (%slot-definition-initargs  dslot))
     525                             (pushnew dslot-arg initargs :test #'eq)))))
     526             (eslotd
     527               (make-effective-slot-definition
     528                class
     529                :name name
     530                :allocation :instance
     531                :type (or (%slot-definition-type first) t)
     532                :documentation (when documentor (nth-value
     533                                      1
     534                                      (%slot-definition-documentation
     535                                       documentor)))
     536                :class (%slot-definition-class first)
     537                :initargs initargs
     538                :initfunction (if initer
     539                                (%slot-definition-initfunction initer))
     540                :initform (if initer (%slot-definition-initform initer))
     541                :foreign-type (foreign-slot-definition-foreign-type first))))
    431542      (multiple-value-bind (getter setter) (compute-foreign-slot-accessors eslotd)
    432543        (setf (foreign-slot-definition-getter eslotd) getter)
    433         (setf (foreign-slot-definition-setter eslotd) setter)))
    434     eslotd))
     544        (setf (foreign-slot-definition-setter eslotd) setter))
     545      eslotd))))
    435546
    436547
    437548;;; Determine the location of each slot
     549;;; An effective slot's location is
     550;;; a) a function of the class's origin (superclass-instance-size)
     551;;;    and the corresponding direct class's offset, if it's defined in the
     552;;;    class (has a corresponding direct-slot-definition in the class)
     553;;; b) Exactly the same as the superclass's version's location, because
     554;;;    of single inheritance.
     555
     556(defun determine-foreign-slot-location (class slot-name)
     557  (or
     558   (let* ((origin (superclass-instance-size class)))
     559     (dolist (d (class-direct-slots class))
     560       (when (and (eq slot-name (slot-definition-name d))
     561                   (typep d 'foreign-direct-slot-definition))
     562          (return (+ origin
     563                     (ldb objc-bitfield-offset-byte-offset
     564                          (foreign-direct-slot-definition-offset d)))))))
     565   (dolist (super (class-direct-superclasses class))
     566     (when (typep super 'objc:objc-class) ; can be at most 1
     567       (let* ((e (find slot-name (class-slots super) :key #'slot-definition-name)))
     568         (when e (return (slot-definition-location e))))))
     569   (error "Can't find slot definition for ~s in ~s" slot-name class)))
     570         
    438571
    439572(defmethod compute-slots :around ((class objc:objc-class-object))
     
    448581      (setq instance-slots
    449582            (sort-effective-instance-slotds instance-slots class cpl))
    450       (format t "Instance slots: ~S~%Class Slots: ~S~%Foreign Slots: ~S~%"
    451               instance-slots class-slots foreign-slots)
     583      (when *objc-clos-debug*
     584        (format t "Instance slots: ~S~%Class Slots: ~S~%Foreign Slots: ~S~%"
     585                instance-slots class-slots foreign-slots))
    452586      (loop for islot in instance-slots
    453587            for loc = 1 then (1+ loc)
     
    460594      (dolist (fslot foreign-slots)
    461595        (setf (%slot-definition-location fslot)
    462               (%objc-ivar-offset
    463                (compute-objc-variable-name (%slot-definition-name fslot)) class)))
     596              (determine-foreign-slot-location
     597               class
     598               (%slot-definition-name fslot))))
    464599      (append instance-slots class-slots foreign-slots))))
    465600
     
    503638(defmethod make-instance ((class objc:objc-class-object) &rest initargs)
    504639  (let ((instance (apply #'allocate-instance class initargs)))
    505     (apply #'initialize-instance instance initargs)
    506     instance))
    507 
    508 (defmethod allocate-instance ((class objc:objc-class) &key &allow-other-keys)
     640    (apply #'initialize-instance instance initargs)))
     641
     642(defun remove-slot-initargs (class initargs)
     643  (let* ((slot-initargs (class-slot-initargs class))) ; cache this, maybe
     644    (collect ((non-slot-initargs))
     645      (do* ((key (pop initargs) (pop initargs))
     646            (val (pop initargs) (pop initargs)))
     647           ((null initargs) (non-slot-initargs))
     648        (unless (member key slot-initargs :test #'eq)
     649          (non-slot-initargs key)
     650          (non-slot-initargs val))))))
     651
     652(defmethod allocate-instance ((class objc:objc-class) &rest initargs &key &allow-other-keys)
    509653  (unless (class-finalized-p class)
    510654    (finalize-inheritance class))
    511   (let* ((instance (%send class 'alloc)) ; For now; Use SEND macro eventually
    512          (len (length (%wrapper-instance-slots (class-own-wrapper class))))
    513          (slot-vector
    514           (allocate-typed-vector :slot-vector (1+ len) (%slot-unbound-marker))))
    515     (setf (slot-vector.instance slot-vector) instance)
    516     (setf (gethash instance *objc-object-slot-vectors*) slot-vector)
    517     instance))
     655  (let* ((instance
     656          (multiple-value-bind (ks vs) (keys-and-vals (remove-slot-initargs
     657                                                       class
     658                                                       initargs))
     659            (apply #'%send ; For now; Use SEND macro eventually
     660                   (%send class 'alloc) (lisp-to-objc-init ks) vs))))
     661    (unless (%null-ptr-p instance)
     662      (let* ((len (length (%wrapper-instance-slots (class-own-wrapper class))))
     663             (slot-vector
     664              (unless (zerop len)
     665                (allocate-typed-vector :slot-vector (1+ len) (%slot-unbound-marker)))))
     666        (setf (slot-vector.instance slot-vector) instance)
     667        (setf (gethash instance *objc-object-slot-vectors*) slot-vector)
     668        (terminate-when-unreachable instance)
     669        (retain-obcj-object instance)
     670        instance))))
     671
     672(defmethod terminate ((instance objc:objc-object))
     673  (objc-message-send instance "release"))
     674
     675
    518676
    519677(defmethod initialize-instance ((instance objc:objc-object) &rest initargs)
     
    522680(defmethod reinitialize-instance ((instance objc:objc-object) &rest initargs)
    523681  (apply #'shared-initialize instance nil initargs))
     682
     683(defmethod initialize-instance :after ((class objc:objc-class) &rest initargs)
     684  (declare (ignore initargs))
     685  (unless (slot-value class 'foreign)
     686    (multiple-value-bind (ivars instance-size)
     687        (%make-objc-ivars class)
     688      (%add-objc-class class ivars instance-size))))
    524689
    525690(defmethod shared-initialize ((instance objc:objc-object) slot-names
    526691                              &rest initargs)
    527692  (let ((class (class-of instance)))
    528     ;; Call appropriate ObjC init method
    529     (multiple-value-bind (ks vs) (keys-and-vals initargs)
    530       (apply #'%send instance (lisp-to-objc-init ks) vs))
    531693    ;; Initialize CLOS slots
    532694    (dolist (slotd (class-slots class))
     
    554716    instance))
    555717
     718(defmethod shared-initialize :after ((spec foreign-effective-slot-definition)
     719                                     slot-names
     720                                     &key &allow-other-keys)
     721  (declare (ignore slot-names))
     722  (setf (slot-value spec 'type-predicate) #'true))
     723
     724;;; The CLASS-OF an existing OBJC:OBJC-CLASS is an OBJC:OBJC-METACLASS,
     725;;; but not necessarily the one specified as a :metaclass option to
     726;;; DEFCLASS or ENSURE-CLASS.  Allow an existing class to be reinitialized,
     727;;; as long as the specified :metaclass and the class's own class have
     728;;; the same metaclass and specified metaclass is a root class.
     729
     730(defmethod ensure-class-using-class ((class objc:objc-class)
     731                                     name
     732                                     &rest keys &key)
     733  (multiple-value-bind (metaclass initargs)
     734      (ensure-class-metaclass-and-initargs class keys)
     735    (let* ((existing-metaclass (class-of class)))
     736      (if (and (eq (class-of metaclass)
     737                   (class-of existing-metaclass))
     738               ;; A root metaclass has the corresponding class as
     739               ;; its superclass, and that class has no superclass.
     740               (with-macptrs ((super (pref metaclass :objc_class.super_class)))
     741                 (and (not (%null-ptr-p super))
     742                      (not (%objc-metaclass-p super))
     743                      (%null-ptr-p (pref super :objc_class.super_class)))))
     744        ;; Whew! it's ok to reinitialize the class.
     745        (progn
     746          (apply #'reinitialize-instance class initargs)
     747          (setf (find-class name) class))
     748        (error "Can't change metaclass of ~s to ~s." class metaclass)))))
     749
     750 
    556751
    557752;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     
    570765;;; already existing subclass of OBJC:OBJC-CLASS
    571766
     767
     768 
     769 
     770
    572771(defun compute-objc-variable-name (sym)
    573772  (let* ((pname (string sym))
     
    579778
    580779(defmethod allocate-instance ((metaclass objc:objc-metaclass)
    581                               &key name direct-superclasses direct-slots
     780                              &key name direct-superclasses
    582781                              &allow-other-keys)
    583   (let ((class-name (compute-objc-classname name))
    584         (superclass-name
     782  (let ((superclass
    585783         (loop for s in direct-superclasses
    586784               when (typep s 'objc:objc-class)
     
    588786               finally
    589787               (if (= (length objc-supers) 1)
    590                    (return (compute-objc-classname (class-name (first objc-supers))))
     788                   (return (first objc-supers))
    591789                 (error "Exactly one OBJC:OBJC-CLASS must appear in ~S, found ~S"
    592790                        direct-superclasses
    593                         (length objc-supers)))))
    594         (ivars
    595          (loop for splist in direct-slots
    596                when (getf splist :foreign)
    597                  collect (list (compute-objc-variable-name (getf splist :name))
    598                                (or (getf splist :type) :id)))))
    599     (%define-objc-class (note-objc-class class-name superclass-name ivars))))
    600 
    601 (defmethod shared-initialize ((class objc:objc-class) slot-names &rest initargs)
    602   ;; *** validate superclasses
    603   ;; *** create direct slot definition objects
    604   ;; *** dependency maintenance
    605   ;; *** maybe finalize inheritance
    606   class)
     791                        (length objc-supers))))))
     792    (%allocate-objc-class name superclass)))
     793
     794(defmethod shared-initialize ((class objc:objc-class-object) slot-names &rest initargs)
     795  (%shared-initialize class slot-names initargs))
    607796
    608797(defmethod validate-superclass ((c1 objc:objc-class) (c2 objc:objc-class))
     
    618807  class)
    619808
     809;;; Reader/writer methods for instances of OBJC:OBJC-CLASS
     810(defmethod reader-method-class ((class objc:objc-class)
     811                                (dslotd direct-slot-definition)
     812                                &rest initargs)
     813  (declare (ignore initargs))
     814  (find-class 'standard-reader-method))
     815
     816(defmethod writer-method-class ((class objc:objc-class)
     817                                (dslotd direct-slot-definition)
     818                                &rest initargs)
     819  (declare (ignore initargs))
     820  (find-class 'standard-reader-method))
Note: See TracChangeset for help on using the changeset viewer.