diff options
-rw-r--r-- | Lisp/method-invocation.lisp | 131 |
1 files changed, 26 insertions, 105 deletions
diff --git a/Lisp/method-invocation.lisp b/Lisp/method-invocation.lisp index 879996d..5601edf 100644 --- a/Lisp/method-invocation.lisp +++ b/Lisp/method-invocation.lisp @@ -241,111 +241,32 @@ easier to use with __apply__. (defun primitive-invoke (receiver method-name return-type &rest args) - "An invocation mechanism with ad-hoc argument conversion." - (with-foreign-string-pool (register-temporary-string) - (let* ((raw-argc (the argument-number (length args))) - (real-argc (+ raw-argc 2)) - (return-c-type (case return-type - ((id objective-c-class exception selector) :pointer) - (otherwise return-type))) - (selector (if (typep method-name 'selector) - method-name - (find-selector method-name)))) - (labels ((alloc-string-and-register (string) - (register-temporary-string - (cffi:foreign-string-alloc string)))) - ;; We allocate a conservatively-sized buffer for arguments of - ;; primitive types called OBJC-ARG-BUFFER. Non-primitive types - ;; don't need allocation, anyway, because we can just pass the - ;; pointer directly. It's unfortunate that we can't do this for - ;; `id' values, because we can't just pass a pointer to the `id' - ;; SAP (which would be highly implementation-dependent and might - ;; even change at any time, especially during GC). - ;; - ;; In any case, OBJC-ARGS-PTRS is the array of pointers which - ;; the libffi docs call AVALUES. It must therefore contain - ;; pointers pointing into the argument buffer (or, in the case - ;; of a newly allocated C string, to that string). This is what - ;; the DOTIMES form below tries to ensure. - (cffi:with-foreign-objects ((arg-types '(:pointer :char) - (the fixnum (length args))) - (objc-arg-ptrs '(:pointer :void) - real-argc) - (return-value-cell (if (eq return-c-type :void) - :int - return-c-type)) - (objc-arg-buffer +pessimistic-allocation-type+ - real-argc)) - (dotimes (i real-argc) - (setf (cffi:mem-aref objc-arg-ptrs '(:pointer :void) i) - (cffi:inc-pointer objc-arg-buffer - (* i +pessimistic-allocation-size+)))) - (macrolet ((argref (type num) - `(cffi:mem-ref objc-arg-buffer ,type - (* ,num +pessimistic-allocation-size+)))) - (flet ((ad-hoc-arglist->objc-arglist! (args) - (setf (argref '(:pointer :void) 0) - (if (pointerp receiver) - receiver - (pointer-to receiver)) - (argref '(:pointer :void) 1) - (pointer-to selector)) - (loop for arg in args - for i from 0 to raw-argc - do (let* ((type-name (lisp-value->type-name arg))) - (typecase arg - ;; According to Allegro CL, strings - ;; are POINTERP (and thus elements of - ;; the C-POINTER type), so they have - ;; to come first in this TYPECASE - ;; form. Weird. - ;; - ;; By the way, pointers are - ;; represented as integers in Allegro - ;; CL, so all integers are POINTERP, - ;; too. - (string - (setf (argref :string (+ i 2)) - (alloc-string-and-register arg))) - ((or c-pointer-wrapper - c-pointer) - (setf (argref :pointer (+ i 2)) - (typecase arg - (c-pointer-wrapper (pointer-to arg)) - (t arg)))) - (t (setf (argref (type-name->c-type type-name) - (+ i 2)) - arg))) - (setf (cffi:mem-aref arg-types '(:pointer :char) i) - (alloc-string-and-register - (type-name->type-id type-name))))))) - (ad-hoc-arglist->objc-arglist! args) - (let ((error-cell - (%objcl-invoke-with-types raw-argc - (type-name->type-id return-type) - arg-types - return-value-cell - objc-arg-ptrs))) - (unless (cffi:null-pointer-p error-cell) - ;; Note that we do not FOREIGN-FREE the error cell, - ;; because it is either a null pointer or a pointer to - ;; an Objective-C object. In the latter case, - ;; INITIALIZE-INSTANCE does the memory management for - ;; us. - (error (make-pointer-wrapper 'exception :pointer error-cell))) - (case return-type - ((id objective-c-class exception selector) - (let ((*skip-retaining* - (or *skip-retaining* - (constructor-name-p (selector-name selector)))) - (pointer (cffi:mem-ref return-value-cell - return-c-type))) - (if (cffi:null-pointer-p pointer) - nil - (make-pointer-wrapper return-type :pointer pointer)))) - ((:void) (values)) - (otherwise (cffi:mem-ref return-value-cell - return-c-type))))))))))) + (flet ((ad-hoc-value->typespec (arg) + (typecase arg + ;; According to Allegro CL, strings + ;; are POINTERP (and thus elements of + ;; the C-POINTER type), so they have + ;; to come first in this TYPECASE + ;; form. Weird. + ;; + ;; By the way, pointers are + ;; represented as integers in Allegro + ;; CL, so all integers are POINTERP, + ;; too. + (string '(:string ())) + (c-pointer-wrapper '(id ())) + (c-pointer '(:pointer ())) + (t `(,return-type ()))))) + (let ((return-typespec `(,return-type ())) + (arg-typespecs (mapcar #'ad-hoc-value->typespec args))) + (low-level-invoke receiver + (selector method-name) + (type-name->type-id (car return-typespec)) + return-typespec + (mapcar #'type-name->type-id (mapcar #'car arg-typespecs)) + arg-typespecs + (+ 2 (length args)) + args)))) (define-cached-function retrieve-method-signature-info |