Changeset 5865
- Timestamp:
- Feb 2, 2007, 1:32:47 AM (18 years ago)
- Location:
- trunk/ccl/examples
- Files:
-
- 4 edited
-
bridge.lisp (modified) (8 diffs)
-
objc-clos.lisp (modified) (1 diff)
-
objc-runtime.lisp (modified) (11 diffs)
-
objc-support.lisp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ccl/examples/bridge.lisp
r5733 r5865 359 359 360 360 (defun result-type-requires-structure-return (result-type) 361 (and (typep result-type 'foreign-record-type) 362 (> (ensure-foreign-type-bits result-type) 32))) 361 ;; Use objc-msg-send-stret for all methods that return 362 ;; record types. 363 (typep result-type 'foreign-record-type)) 363 364 364 365 (defun postprocess-objc-message-info (message-info) … … 455 456 (lookup-objc-message-info message-name info) 456 457 (postprocess-objc-message-info info)) 457 *objc-message-info*)) 458 *objc-message-info*) 459 ;; Update info about init messages. 460 (register-objc-init-messages)) 458 461 459 462 … … 496 499 497 500 498 499 500 501 501 ;;; TRANSLATE-FOREIGN-ARG-TYPE doesn't accept :VOID 502 502 … … 508 508 509 509 510 ;;; Convert a Lisp object X to a desired foreign type FTYPE 511 ;;; The following conversions are currently done: 512 ;;; - T/NIL => #$YES/#$NO 513 ;;; - NIL => (%null-ptr) 514 ;;; - Lisp string => NSString 515 ;;; - Lisp numbers => SINGLE-FLOAT when possible 516 517 (defmacro coerce-to-bool (x) 518 (let ((x-temp (gensym))) 519 `(let ((,x-temp ,x)) 520 (if (or (eq ,x-temp 0) (null ,x-temp)) #$NO #$YES)))) 521 522 (defmacro coerce-to-address (x) 523 (let ((x-temp (gensym))) 524 `(let ((,x-temp ,x)) 525 (cond ((null ,x-temp) (%null-ptr)) 526 ((stringp ,x-temp) (%make-nsstring ,x-temp)) 527 (t ,x-temp))))) 528 529 (defmacro coerce-to-foreign-type (x ftype) 530 (cond ((and (constantp x) (constantp ftype)) 531 (case ftype 532 (:id (if (null x) `(%null-ptr) (coerce-to-address x))) 533 (:<BOOL> (coerce-to-bool (eval x))) 534 (t x))) 535 ((constantp ftype) 536 (case ftype 537 (:id `(coerce-to-address ,x)) 538 (:<BOOL> `(coerce-to-bool ,x)) 539 (t x))) 540 (t `(case ,(if (atom ftype) ftype) 541 (:id (coerce-to-address ,x)) 542 (:<BOOL> (coerce-to-bool ,x)) 543 (t ,x))))) 544 545 ;;; Convert a foreign object X to T or NIL 546 547 (defun coerce-from-bool (x) 548 (cond 549 ((eq x #$NO) nil) 550 ((eq x #$YES) t) 551 (t (error "Cannot coerce ~S to T or NIL" x)))) 552 553 554 ;;; Convert a set of ARGS with given foreign types to an argspec suitable 555 ;;; for %FF-CALL 556 557 (defun convert-to-argspecs (argtypes result-ftype args evalargs) 558 (setq argtypes (mapcar #'fudge-objc-type argtypes)) 559 (setq result-ftype (fudge-objc-type result-ftype)) 560 (flet ((foo (ftype &optional for-result) 561 (let* ((translated 562 (if (member ftype 563 '(:unsigned-doubleword :signed-doubleword) 564 :test #'eq) 565 ftype 566 (if for-result 567 (translate-foreign-result-type ftype) 568 (translate-foreign-arg-type ftype))))) 569 (if (and (consp translated) (eq (first translated) :record)) 570 #+apple-objc 571 (ceiling (second translated) target::nbits-in-word) 572 #+gnu-objc `(:* ,ftype) 573 translated)))) 574 (nconc 575 (loop 576 for a in args 577 for ftype in argtypes 578 do (ensure-foreign-type-bits (parse-foreign-type ftype)) 579 append (list (foo ftype) 580 (if evalargs 581 (coerce-to-foreign-type a 582 #+apple-objc ftype 583 #+gnu-objc (foo ftype)) 584 `(coerce-to-foreign-type ,a #+apple-objc ,ftype #+gnu-objc ,(foo ftype))))) 585 (list (foo result-ftype t))))) 586 587 588 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 589 ;;;; Boolean Return Hackery ;;;; 590 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 510 511 591 512 592 513 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; … … 827 748 (arg (car args))) 828 749 (specs reptype) 829 (case reptype 830 (:<BOOL> (specs `(coerce-to-bool ,arg))) 831 (:id (specs `(coerce-to-address ,arg))) 832 (t (specs arg))))) 750 (specs arg))) 833 751 ;;(break "~& arglist = ~s" arglist) 834 752 (if (result-type-requires-structure-return … … 847 765 `(objc-message-send-super ,super ,msg ,@arglist ,result-spec) 848 766 `(objc-message-send ,o ,msg ,@arglist ,result-spec)))) 849 (if (eq result-spec :<BOOL>) 850 `(coerce-from-bool ,form) 851 form))))))) 767 form)))))) 852 768 853 769 (defun build-call-from-method-info (method-info args vargs o msg svarforms sinitforms s super) … … 864 780 super)))) 865 781 866 867 868 ;;; The %SEND and %SEND/STRET functions for sending general messages869 870 (defmacro make-general-send (o msg args &optional s super sclassname)871 (declare (ignorable sclassname))872 `(let ((vargs nil))873 (with-ns-exceptions-as-errors874 ;; Ensure that MSG is a string875 (multiple-value-setq (msg args vargs) (%parse-message (cons ,msg ,args)))876 (check-type ,msg string) ; What else could it be ?877 (let* ((message-info (get-objc-message-info ,msg))878 (message-accepts-varargs879 (getf (objc-message-info-flags message-info)880 :accepts-varargs)))881 ;; If a vararg exists, make sure that the message can accept it882 (when (and vargs (not message-accepts-varargs))883 (error "Message ~S cannot accept a variable number of arguments" msg))884 ;; Lookup method signature. We can do a runtime type dispatch885 ;; on the receiver (if there's any ambiguity) even if we're doing886 ;; some flavor of SEND-SUPER, since the next method must have887 ;; the same type signature as the receiver.888 (let* ((method-info (%lookup-objc-method-info message-info ,o))889 (sel (get-selector ,msg)))890 ;; Check arg count891 (unless (= (length ,args) (objc-message-info-req-args message-info))892 (error "Message ~S requires ~a ~d args, but ~d were provided."893 (if vargs "at least" "exactly")894 (objc-message-info-req-args message-info)895 (length args)))896 ;; Get method type signature897 (let* ((mtsig (objc-method-info-signature method-info))898 (argtypes (rest mtsig))899 (result-type (first mtsig))900 (argspecs1 (convert-to-argspecs argtypes result-type ,args t))901 (argspecs (append (butlast argspecs1) vargs (last argspecs1)))902 (result-spec (first (last argspecs))))903 ;; Yes, we're doing all of this at runtime. Don't even get904 ;; me started on %FF-CALL.905 ;; Call method906 (if (requires-stret-p result-spec)907 ,(if (null s)908 ;; STRET required but not provided909 `(error "The message ~S must be sent using SEND/STRET" ,msg)910 ;; STRET required and provided911 (if (null super)912 ;; Regular stret send, invoke objc_msgSend_stret913 `(progn914 (apply #'%ff-call915 (%reference-external-entry-point916 (load-time-value917 (external "_objc_msgSend_stret")))918 :address ,s919 :address ,o920 :address sel921 (progn (setf (car (last argspecs)) :void) argspecs))922 ,s)923 ;; Stret send to super, invoke objc_msgSendSuper_stret924 `(progn925 (apply #'%ff-call926 (%reference-external-entry-point927 (load-time-value928 (external "_objc_msgSendSuper_stret")))929 :address ,s930 :address ,super931 :address sel932 (progn (setf (car (last argspecs)) :void) argspecs)))))933 ,(if (null s)934 ;; STRET not required and not provided935 (if (null super)936 ;; Regular send, invoke objc_msgSend937 `(let ((r (apply #'%ff-call938 (%reference-external-entry-point939 (load-time-value940 (external "_objc_msgSend")))941 :address ,o942 :address sel943 argspecs)))944 (if (eq result-type :<BOOL>)945 (coerce-from-bool r)946 r))947 ;;; Send to super, invoke objc_msgSendSuper948 `(let ((r (apply #'%ff-call949 (%reference-external-entry-point950 (load-time-value951 (external "_objc_msgSendSuper")))952 :address ,super953 :address sel954 argspecs)))955 (if (eq result-type :<BOOL>)956 (coerce-from-bool r)957 r)))958 ;; STRET not required but provided959 `(error "The message ~S must be sent using SEND" msg)))))))))960 961 (defun %send (o msg &rest args)962 (declare (optimize (speed 3)) (dynamic-extent args))963 (make-general-send o msg args))964 965 (defun %send/stret (s o msg &rest args)966 (declare (optimize (speed 3)) (dynamic-extent args))967 (make-general-send o msg args s))968 782 969 783 … … 980 794 (when (not (stringp cname)) 981 795 (setf cname (lisp-to-objc-classname cname))) 982 (apply #'%send 983 (send (find-objc-class cname) 'alloc) 984 (lisp-to-objc-init ks) 985 vs))) 986 987 796 (send-objc-init-message (send (find-objc-class cname) 'alloc) 797 ks 798 vs))) 988 799 989 800 ;;; Provide the BRIDGE module -
trunk/ccl/examples/objc-clos.lisp
r5729 r5865 747 747 class 748 748 initargs)) 749 ; The second %SEND below should be SEND eventually 750 (apply #'%send (%send class 'alloc) (lisp-to-objc-init ks) vs)))) 749 (send-objc-init-message (allocate-objc-object class) ks vs)))) 751 750 (unless (%null-ptr-p instance) 752 751 (let* ((raw-ptr (raw-macptr-for-instance instance)) -
trunk/ccl/examples/objc-runtime.lisp
r5728 r5865 954 954 `(load-objc-selector ,(objc-selector-name s))) 955 955 956 957 ;;; Convert a Lisp object X to a desired foreign type FTYPE 958 ;;; The following conversions are currently done: 959 ;;; - T/NIL => #$YES/#$NO 960 ;;; - NIL => (%null-ptr) 961 ;;; - Lisp string => NSString 962 ;;; - Lisp numbers => SINGLE-FLOAT when possible 963 964 (defmacro coerce-to-bool (x) 965 (let ((x-temp (gensym))) 966 `(let ((,x-temp ,x)) 967 (if (or (eq ,x-temp 0) (null ,x-temp)) #.#$NO #.#$YES)))) 968 969 (defmacro coerce-to-address (x) 970 (let ((x-temp (gensym))) 971 `(let ((,x-temp ,x)) 972 (cond ((null ,x-temp) (%null-ptr)) 973 ((stringp ,x-temp) (%make-nsstring ,x-temp)) 974 (t ,x-temp))))) 975 976 (defmacro coerce-to-foreign-type (x ftype) 977 (cond ((and (constantp x) (constantp ftype)) 978 (case ftype 979 (:id (if (null x) `(%null-ptr) (coerce-to-address x))) 980 (:<BOOL> (coerce-to-bool (eval x))) 981 (t x))) 982 ((constantp ftype) 983 (case ftype 984 (:id `(coerce-to-address ,x)) 985 (:<BOOL> `(coerce-to-bool ,x)) 986 (t x))) 987 (t `(case ,(if (atom ftype) ftype) 988 (:id (coerce-to-address ,x)) 989 (:<BOOL> (coerce-to-bool ,x)) 990 (t ,x))))) 991 992 (defun objc-arg-coerce (typespec arg) 993 (coerce-to-foreign-type arg typespec)) 994 995 996 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 997 ;;;; Boolean Return Hackery ;;;; 998 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 999 1000 ;;; Convert a foreign object X to T or NIL 1001 1002 (defun coerce-from-bool (x) 1003 (cond 1004 ((eq x #$NO) nil) 1005 ((eq x #$YES) t) 1006 (t (error "Cannot coerce ~S to T or NIL" x)))) 1007 1008 (defun objc-result-coerce (type result) 1009 (cond ((eq type :<BOOL>) 1010 `(coerce-from-bool ,result)) 1011 (t result))) 1012 956 1013 ;;; Add a faster way to get the message from a SEL by taking advantage of the 957 1014 ;;; fact that a selector is really just a canonicalized, interned C string … … 977 1034 (setq argspecs (append argspecs '(:id)))) 978 1035 #+apple-objc 979 `(external-call "_objc_msgSend" 980 :id ,receiver 981 :<SEL> (@selector ,selector-name) 982 ,@argspecs) 1036 (funcall (ftd-ff-call-expand-function *target-ftd*) 1037 `(external-call "_objc_msgSend") 1038 `(:id ,receiver :<SEL> (@selector ,selector-name) ,@argspecs) 1039 :arg-coerce 'objc-arg-coerce 1040 :result-coerce 'objc-result-coerce) 983 1041 #+gnu-objc 984 1042 (let* ((r (gensym)) … … 991 1049 :<SEL> ,s 992 1050 :<IMP>))) 993 (ff-call ,imp :id ,r :<SEL> ,s ,@argspecs)))) 994 995 ;;; A method that returns a structure (whose size is > 4 bytes on 996 ;;; darwin, in all cases on linuxppc) does so by copying the structure 997 ;;; into a pointer passed as its first argument; that means that we 998 ;;; have to invoke the method via #_objc_msgSend_stret in the #+apple-objc 999 ;;; case. 1051 (funcall (ftd-ff-call-expand-function *target-ftd*) 1052 `(%ff-call ,imp) 1053 `(:id ,receiver :<SEL> (@selector ,selector-name) ,@argspecs) 1054 :arg-coerce 'objc-arg-coerce 1055 :result-coerce 'objc-result-coerce)))) 1056 1057 ;;; A method that returns a structure does so by platform-dependent 1058 ;;; means. One of those means (which is fairly common) is to pass a 1059 ;;; pointer to an instance of a structure type as a first argument to 1060 ;;; the method implementation function (thereby making SELF the second 1061 ;;; argument, etc.), but whether or not it's actually done that way 1062 ;;; depends on the platform and on the structure type. The special 1063 ;;; variable CCL::*TARGET-FTD* holds a structure (of type 1064 ;;; CCL::FOREIGN-TYPE-DATA) which describes some static attributes of 1065 ;;; the foreign type system on the target platform and contains some 1066 ;;; functions which can determine dynamic ABI attributes. One such 1067 ;;; function can be used to determine whether or not the "invisible 1068 ;;; first arg" convention is used to return structures of a given 1069 ;;; foreign type; another function in *TARGET-FTD* can be used to 1070 ;;; construct a foreign function call form that handles 1071 ;;; structure-return and structure-types-as-arguments details. In the 1072 ;;; Apple ObjC runtime, #_objc_msgSend_stret must be used if the 1073 ;;; invisible-first-argument convention is used to return a structure 1074 ;;; and must NOT be used otherwise. (The Darwin ppc64 and all 1075 ;;; supported x86-64 ABIs often use more complicated structure return 1076 ;;; conventions than ppc32 Darwin or ppc Linux.) We should use 1077 ;;; OBJC-MESSAGE-SEND-STRET to send any message that returns a 1078 ;;; structure or union, regardless of how that structure return is 1079 ;;; actually implemented. 1000 1080 1001 1081 (defmacro objc-message-send-stret (structptr receiver selector-name &rest argspecs) 1002 (if (evenp (length argspecs)) 1003 (setq argspecs (append argspecs '(:void))) 1004 (unless (member (car (last argspecs)) '(:void nil)) 1005 (error "Invalid result spec for structure return: ~s" 1006 (car (last argspecs))))) 1007 #+apple-objc 1008 `(external-call "_objc_msgSend_stret" 1009 :address ,structptr 1010 :id ,receiver 1011 :<SEL> (@selector ,selector-name) 1012 ,@argspecs) 1082 #+apple-objc 1083 (let* ((return-typespec (car (last argspecs))) 1084 (entry-name (if (funcall (ftd-ff-call-struct-return-by-implicit-arg-function *target-ftd*) return-typespec) 1085 "_objc_msgSend_stret" 1086 "_objc-msgSend"))) 1087 (funcall (ftd-ff-call-expand-function *target-ftd*) 1088 `(%ff-call (external ,entry-name)) 1089 `(,structptr :id ,receiver :<SEL> (@selector ,selector-name) ,@argspecs) 1090 :arg-coerce 'objc-arg-coerce 1091 :result-coerce 'objc-result-coerce)) 1013 1092 #+gnu-objc 1014 1093 (let* ((r (gensym)) … … 1021 1100 :<SEL> ,s 1022 1101 :<IMP>))) 1023 (ff-call ,imp :address ,structptr :id ,r :<SEL> ,s ,@argspecs)))) 1102 , (funcall (ftd-ff-call-expand-function *target-ftd*) 1103 `(%ff-call ,imp) 1104 `(,structptr :id , :<SEL> ,s ,@argspecs) 1105 :arg-coerce 'objc-arg-coerce 1106 :result-coerce 'objc-result-coerce)))) 1024 1107 1025 1108 ;;; #_objc_msgSendSuper is similar to #_objc_msgSend; its first argument … … 1031 1114 (setq argspecs (append argspecs '(:id)))) 1032 1115 #+apple-objc 1033 `(external-call "_objc_msgSendSuper" 1034 :address ,super 1035 :<SEL> (@selector ,selector-name) 1036 ,@argspecs) 1116 (funcall (ftd-ff-call-expand-function *target-ftd*) 1117 `(%ff-call (external "_objc_msgSendSuper")) 1118 `(:address ,super :<SEL> (@selector ,selector-name) ,@argspecs) 1119 :arg-coerce 'objc-arg-coerce 1120 :result-coerce 'objc-result-coerce) 1037 1121 #+gnu-objc 1038 1122 (let* ((sup (gensym)) … … 1045 1129 :<SEL> ,sel 1046 1130 :<IMP>))) 1047 (ff-call ,imp 1048 :id (pref ,sup :<S>uper.self) 1049 :<SEL> ,sel 1050 ,@argspecs)))) 1051 1052 ;;; Send to superclass method, returning a structure. 1131 (funcall (ftd-ff-call-expand-function *target-ftd*) 1132 `(%ff-call ,imp) 1133 `(:id (pref ,sup :<S>uper.self) 1134 :<SEL> ,sel 1135 ,@argspecs))))) 1136 1137 ;;; Send to superclass method, returning a structure. See above. 1053 1138 (defmacro objc-message-send-super-stret 1054 1139 (structptr super selector-name &rest argspecs) 1055 (if (evenp (length argspecs))1056 (setq argspecs (append argspecs '(:void)))1057 (unless (member (car (last argspecs)) '(:void nil))1058 (error "Invalid result spec for structure return: ~s"1059 (car (last argspecs)))))1060 1140 #+apple-objc 1061 `(external-call "_objc_msgSendSuper_stret" 1062 :address ,structptr 1063 :address ,super 1064 :<SEL> (@selector ,selector-name) 1065 ,@argspecs) 1141 (let* ((return-typespec (car (last argspecs))) 1142 (entry-name (if (funcall (ftd-ff-call-struct-return-by-implicit-arg-function *target-ftd*) return-typespec) 1143 "_objc_msgSendSuper_stret" 1144 "_objc-msgSendSuper"))) 1145 (funcall (ftd-ff-call-expand-function *target-ftd*) 1146 `(%ff-call (external ,entry-name)) 1147 `(,structptr :address ,super :<SEL> (@selector ,selector-name) ,@argspecs) 1148 :arg-coerce 'objc-arg-coerce 1149 :result-coerce 'objc-result-coerce)) 1066 1150 #+gnu-objc 1067 1151 (let* ((sup (gensym)) … … 1074 1158 :<SEL> ,sel 1075 1159 :<IMP>))) 1076 (ff-call ,imp 1077 :address ,structptr 1160 (funcall (ftd-ff-call-expand-function *target-ftd*) 1161 `(%ff-call ,imp) 1162 ,structptr 1078 1163 :id (pref ,sup :<S>uper.self) 1079 1164 :<SEL> ,sel … … 1430 1515 "initWithCString:" :address s))) 1431 1516 1517 1518 (let* ((objc-init-message-args (make-array 10 :fill-pointer 0 :adjustable t))) 1519 (defun %objc-init-message-arg (n) 1520 (let* ((len (length objc-init-message-args))) 1521 (do* ((i len (1+ i))) 1522 ((> i n) (aref objc-init-message-args n)) 1523 (vector-push-extend (intern (format nil "ARG~d" i)) objc-init-message-args))))) 1524 1525 (defun objc-init-message-arglist (n) 1526 (collect ((args)) 1527 (dotimes (i n (args)) (args (%objc-init-message-arg i))))) 1528 1529 1530 (defun %make-objc-init-function-for-signature (signature) 1531 ;; No structure returns or send-supers involved. 1532 (let* ((types (cdr signature)) 1533 (args (objc-init-message-arglist (length types)))) 1534 (collect ((call)) 1535 (dolist (arg args) 1536 (let* ((type (pop types))) 1537 (call type) 1538 (case type 1539 (:<BOOL> (call `(coerce-to-bool ,arg))) 1540 (:id (call `(coerce-to-address ,arg))) 1541 (otherwise (call arg))))) 1542 ;; all "init" messages return :id 1543 (call :id) 1544 (compile nil 1545 `(lambda (self selector ,@args) 1546 #+apple-objc 1547 (external-call "_objc_msgSend" 1548 :id self 1549 :<SEL> (%get-selector selector) 1550 ,@(call)) 1551 #+gnu-objc 1552 (let* ((s (%get-selector selector)) 1553 (imp (external-call "objc_msg_lookup" 1554 :id self 1555 :<SEL> s 1556 :<IMP>))) 1557 (ff-call imp :id self :<SEL> s ,@(call)))))))) 1558 1559 (defstruct objc-init-method-signature-info 1560 signature 1561 function) 1562 1563 (defvar *objc-init-method-signatures* (make-hash-table :test #'equal) 1564 "Maps signature lists to OBJC-INIT-METHOD-SIGNATURE-INFO structures.") 1565 1566 (defun get-objc-init-method-signature-info (list) 1567 (or (gethash list *objc-init-method-signatures*) 1568 (setf (gethash list *objc-init-method-signatures*) 1569 (make-objc-init-method-signature-info 1570 :signature list 1571 :function (%make-objc-init-function-for-signature list))))) 1572 1573 (defstruct objc-init-message-info 1574 selector 1575 method-signature-alist 1576 ) 1577 1578 (defvar *objc-init-messages-for-message-names* (make-hash-table :test #'equal) 1579 "Maps from init message names to OBJC-INIT-MESSAGE-INFO structures.") 1580 1581 (defun register-objc-init-message (message-info) 1582 (when (dolist (m (objc-message-info-methods message-info)) 1583 (unless (getf (objc-method-info-flags m) :protocol) 1584 (let* ((sig (objc-method-info-signature m))) 1585 (unless (eq (car (last sig)) :void) 1586 (when (eq :id (car (objc-method-info-signature m))) 1587 (return t)))))) 1588 (let* ((name (objc-message-info-message-name message-info)) 1589 (init-info 1590 (or (gethash name *objc-init-messages-for-message-names*) 1591 (setf (gethash name *objc-init-messages-for-message-names*) 1592 (make-objc-init-message-info 1593 :selector (load-objc-selector name) 1594 :method-signature-alist nil)))) 1595 (alist (objc-init-message-info-method-signature-alist init-info))) 1596 (dolist (m (objc-message-info-methods message-info)) 1597 (let* ((sig (objc-method-info-signature m))) 1598 (when (and (eq :id (car sig)) 1599 (not (getf (objc-method-info-flags m) :protocol))) 1600 ;; Looks like a real init method. 1601 (let* ((class (canonicalize-registered-class (lookup-objc-class (objc-method-info-class-name m)))) 1602 (siginfo (get-objc-init-method-signature-info sig)) 1603 (pair (assoc siginfo alist :test #'eq))) 1604 (if (null pair) 1605 (push (cons siginfo (list class)) alist) 1606 (pushnew class (cdr pair) :test #'eq)))))) 1607 (setf (objc-init-message-info-method-signature-alist init-info) alist) 1608 init-info))) 1609 1610 (defun send-init-message-with-info (instance init-info args) 1611 (let* ((selector (objc-init-message-info-selector init-info)) 1612 (alist (objc-init-message-info-method-signature-alist init-info)) 1613 (pair (do* ((alist alist (cdr alist))) 1614 ((null (cdr alist)) 1615 (car alist) 1616 (let* ((pair (car alist))) 1617 (dolist (class (cdr pair)) 1618 (when (typep instance class) 1619 (return pair)))))))) 1620 (with-ns-exceptions-as-errors 1621 (apply (objc-init-method-signature-info-function (car pair)) 1622 instance 1623 selector 1624 args)))) 1625 1626 1627 ;;; Register init-message-info for all known init messages. (A 1628 ;;; message is an "init message" if it starts with the string "init", 1629 ;;; accepts a fixed number of arguments, and has at least one declared 1630 ;;; method that returns :ID and is not a protocol method. 1631 (defun register-objc-init-messages () 1632 (do-interface-dirs (d) 1633 (dolist (init (cdb-enumerate-keys (db-objc-methods d) 1634 #'(lambda (string) 1635 (string= string "init" :end1 (min (length string) 4))))) 1636 (register-objc-init-message (get-objc-message-info init))))) 1637 1638 1639 (defvar *objc-init-messages-for-init-keywords* (make-hash-table :test #'equal) 1640 "Maps from lists of init keywords to OBJC-INIT-MESSAGE structures") 1641 1642 (defun send-objc-init-message-with-info (instance init-info args) 1643 (let* ((selector (objc-init-message-info-selector init-info)) 1644 (alist (objc-init-message-info-method-signature-alist init-info)) 1645 (pair (do* ((alist alist (cdr alist))) 1646 ((null (cdr alist)) 1647 (car alist) 1648 (let* ((pair (car alist))) 1649 (dolist (class (cdr pair)) 1650 (when (typep instance class) 1651 (return pair)))))))) 1652 (with-ns-exceptions-as-errors 1653 (apply (objc-init-method-signature-info-function (car pair)) 1654 instance 1655 selector 1656 args)))) 1657 1658 1659 (defun send-objc-init-message (instance init-keywords args) 1660 (let* ((info (gethash init-keywords *objc-init-messages-for-init-keywords*))) 1661 (unless info 1662 (let* ((name (lisp-to-objc-init init-keywords)) 1663 (name-info (gethash name *objc-init-messages-for-message-names*))) 1664 (unless name-info 1665 (error "Unknown ObjC init message: ~s" name)) 1666 (setf (gethash init-keywords *objc-init-messages-for-init-keywords*) 1667 (setq info name-info)))) 1668 (send-objc-init-message-with-info instance info args))) 1669 1670 (defun allocate-objc-object (class) 1671 (send class 'alloc)) 1672 1673 1674 1675 1432 1676 ;;; Return the "canonical" version of P iff it's a known ObjC class 1433 1677 (defun objc-class-p (p) … … 1710 1954 (t (bad-selector "general failure"))) 1711 1955 ;; If the result type is of the form (:STRUCT <typespec> <name>), 1712 ;; make <name> be the first argument (of type :address) and 1713 ;; make the resulttype :void 1956 ;; make <name> be the first argument. 1714 1957 (when (and (consp resulttype) 1715 1958 (eq (car resulttype) :struct)) 1716 1959 (destructuring-bind (typespec name) (cdr resulttype) 1717 (if (and (typep name 'symbol)1718 (typep (parse-foreign-type `(:struct ,typespec))1719 'foreign-record-type))1720 (setq struct-return name1721 resulttype `(:struct ,typespec))1722 (bad-selector "Bad struct return type"))))1960 (let* ((rtype (%foreign-type-or-record typespec))) 1961 (if (and (typep name 'symbol) 1962 (typep rtype 'foreign-record-type)) 1963 (setq struct-return name 1964 resulttype (unparse-foreign-type rtype)) 1965 (bad-selector "Bad struct return type"))))) 1723 1966 (values selector 1724 1967 class-name … … 1766 2009 (params `(:id ,self :<sel> ,_cmd))) 1767 2010 (when struct-return 1768 (setq params `(:address ,struct-return ,@params) 1769 resulttype :void)) 2011 (push struct-return params)) 1770 2012 (setq params (nconc params argspecs)) 1771 2013 `(progn … … 1798 2040 (send-super/stret (s msg &rest args &environment env) 1799 2041 (make-optimized-send nil msg args env s ',super ,class-name))) 1800 (flet ((%send-super (msg &rest args) 1801 (make-general-send nil msg args nil ,super ,class-name)) 1802 (%send-super/stret (s msg &rest args) 1803 (make-general-send nil msg args s ,super ,class-name)) 1804 (super () ,super)) 1805 ,@body)))) 2042 ,@body))) 1806 2043 (%define-lisp-objc-method 1807 2044 ',impname -
trunk/ccl/examples/objc-support.lisp
r5727 r5865 74 74 75 75 (map-objc-classes) 76 (register-objc-init-messages) 76 77 77 78 #+gnu-objc
Note:
See TracChangeset
for help on using the changeset viewer.
