Mercurial > core / lisp/lib/obj/meta/fast.lisp
changeset 698: |
96958d3eb5b0 |
parent: |
10faf95f90dd
|
author: |
Richard Westhaver <ellis@rwest.io> |
date: |
Fri, 04 Oct 2024 22:04:59 -0400 |
permissions: |
-rw-r--r-- |
description: |
fixes |
1 ;;; obj/meta/fast.lisp --- Fast generic functions 3 ;; see https://github.com/marcoheisig/fast-generic-functions 6 (in-package :obj/meta/fast) 8 (deftype local-variable () 9 '(and symbol (not (satisfies constantp)))) 11 (defclass required-info () 14 :reader required-info-variable 16 :initform (required-argument :variable)))) 18 (defclass optional-info () 21 :reader optional-info-variable 23 :initform (required-argument :variable)) 26 :reader optional-info-initform 30 :reader optional-info-suppliedp 31 :type (or null local-variable) 34 (defclass keyword-info () 37 :reader keyword-info-keyword 39 :initform (required-argument :keyword)) 42 :reader keyword-info-variable 44 :initform (required-argument :variable)) 47 :reader keyword-info-initform 51 :reader keyword-info-suppliedp 52 :type (or null local-variable) 55 (defclass auxiliary-info () 58 :reader auxiliary-info-variable 60 :initform (required-argument :variable)) 63 :reader auxiliary-info-initform 66 (defun parse-ordinary-lambda-list (lambda-list) 69 1. A list of REQUIRED-INFO instances, one for each required argument. 71 2. A list of OPTIONAL-INFO instances, one for each optional argument. 73 3. The name of the rest variable, or NIL, if there is none. 75 4. A list of KEYWORD-INFO instances, one for each keyword argument. 77 5. A boolean, indicating whether &allow-other-keys is present. 79 6. A list of AUXILIARY-INFO instances, one for each auxiliary argument. 81 Can parse all but specialized lambda lists. 88 (allow-other-keys-p nil)) 90 (error "Malformed lambda list: ~S" lambda-list)) 91 (parse-required (lambda-list) 92 (unless (endp lambda-list) 93 (let ((item (first lambda-list))) 95 (&optional (parse-&optional (rest lambda-list))) 96 (&rest (parse-&rest (rest lambda-list))) 97 (&key (parse-&key (rest lambda-list))) 98 (&aux (parse-&aux (rest lambda-list))) 99 (#.(set-difference lambda-list-keywords '(&optional &rest &key &aux)) 102 (push (parse-reqired-item item) required) 103 (parse-required (rest lambda-list))))))) 104 (parse-&optional (lambda-list) 105 (unless (endp lambda-list) 106 (let ((item (first lambda-list))) 108 (&rest (parse-&rest (rest lambda-list))) 109 (&key (parse-&key (rest lambda-list))) 110 (&aux (parse-&aux (rest lambda-list))) 111 (#.(set-difference lambda-list-keywords '(&rest &key &aux)) 114 (push (parse-optional-item item) optional) 115 (parse-&optional (rest lambda-list))))))) 116 (parse-&rest (lambda-list) 117 (unless (consp lambda-list) 119 (let ((item (first lambda-list))) 120 (unless (symbolp item) 122 (unless (null rest-var) 125 (unless (endp (rest lambda-list)) 126 (case (first (rest lambda-list)) 127 (&key (parse-&key (rest (rest lambda-list)))) 128 (&aux (parse-&aux (rest (rest lambda-list)))) 129 (otherwise (fail)))))) 130 (parse-&key (lambda-list) 131 (unless (endp lambda-list) 132 (let ((item (first lambda-list))) 134 (&allow-other-keys (parse-&allow-other-keys (rest lambda-list))) 135 (&aux (parse-&aux (rest lambda-list))) 136 (#.(set-difference lambda-list-keywords '(&allow-other-keys &aux)) 139 (push (parse-keyword-item item) keyword) 140 (parse-&key (rest lambda-list))))))) 141 (parse-&allow-other-keys (lambda-list) 142 (setf allow-other-keys-p t) 143 (unless (endp lambda-list) 144 (case (first lambda-list) 145 (&aux (parse-&aux (rest lambda-list))) 148 (parse-&aux (lambda-list) 149 (unless (endp lambda-list) 150 (let ((item (first lambda-list))) 152 (#.lambda-list-keywords (fail)) 154 (push (parse-auxiliary-item item) auxiliary) 155 (parse-&aux (rest lambda-list)))))))) 156 (parse-required lambda-list)) 163 (nreverse auxiliary)))) 165 (defun parse-reqired-item (item) 166 (unless (typep item 'local-variable) 167 (error "Not a valid lambda list variable: ~S" 169 (make-instance 'required-info 172 (defun parse-optional-item (item) 175 (make-instance 'optional-info 177 ((cons local-variable null) 178 (make-instance 'optional-info 179 :variable (first item))) 180 ((cons local-variable (cons t null)) 181 (make-instance 'optional-info 182 :variable (first item) 183 :initform (second item))) 184 ((cons local-variable (cons t (cons local-variable null))) 185 (make-instance 'optional-info 186 :variable (first item) 187 :initform (second item) 188 :suppliedp (third item))) 189 (t (error "Invalid &optional lambda list item: ~S" 192 (defun parse-keyword-item (item) 194 (error "Invalid &key lambda list item: ~S" 196 (parse-keyword-var (item) 199 (values (intern (symbol-name item) :keyword) 202 (values (intern (symbol-name (first item)) :keyword) 204 ((cons keyword (cons symbol null)) 210 (make-instance 'keyword-info 212 :keyword (intern (symbol-name item) :keyword))) 214 (multiple-value-bind (keyword variable) 215 (parse-keyword-var (first item)) 216 (make-instance 'keyword-info 219 ((cons t (cons t null)) 220 (multiple-value-bind (keyword variable) 221 (parse-keyword-var (first item)) 222 (make-instance 'keyword-info 225 :initform (second item)))) 226 ((cons t (cons t (cons local-variable null))) 227 (multiple-value-bind (keyword variable) 228 (parse-keyword-var (first item)) 229 (make-instance 'keyword-info 232 :initform (second item) 233 :suppliedp (third item)))) 236 (defun parse-auxiliary-item (item) 239 (make-instance 'auxiliary-info 241 ((cons local-variable null) 242 (make-instance 'auxiliary-info 243 :variable (first item))) 244 ((cons local-variable (cons t null)) 245 (make-instance 'auxiliary-info 246 :variable (first item) 247 :initform (second item))) 248 (t (error "Invalid &aux lambda list item: ~S" 251 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 253 ;;; Lambda List Unparsing 255 (defun unparse-ordinary-lambda-list 256 (required optional rest-var keyword allow-other-keys-p auxiliary) 258 (unparse-required required) 259 (unparse-optional optional) 260 (unparse-rest rest-var) 261 (unparse-keyword keyword allow-other-keys-p) 262 (unparse-auxiliary auxiliary))) 264 (defun unparse-required (required) 267 (required-info-variable info)) 270 (defun unparse-optional (optional) 276 `(,(optional-info-variable info) 277 ,(optional-info-initform info) 278 ,@(if (optional-info-suppliedp info) 279 `(,(optional-info-suppliedp info)) 283 (defun unparse-keyword (keyword allow-other-keys-p) 284 (if (and (null keyword) 285 (not allow-other-keys-p)) 290 `((,(keyword-info-keyword info) ,(keyword-info-variable info)) 291 ,(keyword-info-initform info) 292 ,@(if (keyword-info-suppliedp info) 293 `(,(keyword-info-suppliedp info)) 296 ,@(if allow-other-keys-p 300 (defun unparse-rest (rest-var) 305 (defun unparse-auxiliary (auxiliary) 311 (list (auxiliary-info-variable info) 312 (auxiliary-info-initform info))) 315 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 317 ;;; Lambda List Info Anonymization 319 (defun anonymize-ordinary-lambda-list (lambda-list) 320 (multiple-value-bind (required optional rest-var keyword allow-other-keys-p auxiliary) 321 (parse-ordinary-lambda-list lambda-list) 322 (unparse-ordinary-lambda-list 323 (mapcar #'anonymize-required-info required) 324 (mapcar #'anonymize-optional-info optional) 327 (gensymify rest-var)) 328 (mapcar #'anonymize-keyword-info keyword) 330 (mapcar #'anonymize-auxiliary-info auxiliary)))) 332 (defun anonymize-required-info (info) 333 (make-instance 'required-info 334 :variable (gensymify (required-info-variable info)))) 336 (defun anonymize-optional-info (info) 337 (make-instance 'optional-info 338 :variable (gensymify (optional-info-variable info)) 339 :initform (optional-info-initform info) 340 :suppliedp (if (optional-info-suppliedp info) 341 (gensymify (optional-info-suppliedp info)) 344 (defun anonymize-keyword-info (info) 345 (make-instance 'keyword-info 346 :variable (gensymify (keyword-info-variable info)) 347 :keyword (keyword-info-keyword info) 348 :initform (keyword-info-initform info) 349 :suppliedp (if (keyword-info-suppliedp info) 350 (gensymify (keyword-info-suppliedp info)) 353 (defun anonymize-auxiliary-info (info) 354 (make-instance 'auxiliary-info 355 :variable (gensymify (auxiliary-info-variable info)) 356 :initform (auxiliary-info-initform info))) 358 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 362 (defun normalize-ordinary-lambda-list (lambda-list) 363 (multiple-value-call #'unparse-ordinary-lambda-list 364 (parse-ordinary-lambda-list lambda-list))) 366 (defun lambda-list-variables (lambda-list) 367 (multiple-value-bind (required optional rest-var keyword allow-other-keys-p auxiliary) 368 (parse-ordinary-lambda-list lambda-list) 369 (declare (ignore allow-other-keys-p)) 370 (let ((variables '())) 371 (dolist (info required) 372 (push (required-info-variable info) variables)) 373 (dolist (info optional) 374 (push (optional-info-variable info) variables) 375 (when (optional-info-suppliedp info) 376 (push (optional-info-suppliedp info) variables))) 377 (unless (null rest-var) 378 (push rest-var variables)) 379 (dolist (info keyword) 380 (push (keyword-info-variable info) variables) 381 (when (keyword-info-suppliedp info) 382 (push (keyword-info-suppliedp info) variables))) 383 (dolist (info auxiliary) 384 (push (auxiliary-info-variable info) variables)) 385 (nreverse variables)))) 387 (defun lambda-list-apply-arguments (lambda-list) 388 (multiple-value-bind (required optional rest-var keyword) 389 (parse-ordinary-lambda-list lambda-list) 391 (mapcar #'required-info-variable required) 392 (mapcar #'optional-info-variable optional) 395 `(,@(loop for info in keyword 396 collect (keyword-info-keyword info) 397 collect (keyword-info-variable info)) 400 ;;; expand-effective-method-body 401 (defun expand-effective-method-body 402 (effective-method generic-function lambda-list) 404 `(let ((.gf. #',(sb-mop:generic-function-name generic-function))) 405 (declare (ignorable .gf.)) 406 (declare (sb-ext:disable-package-locks common-lisp:call-method)) 407 (declare (sb-ext:disable-package-locks common-lisp:make-method)) 408 (declare (sb-ext:disable-package-locks sb-pcl::check-applicable-keywords)) 409 (declare (sb-ext:disable-package-locks sb-pcl::no-primary-method)) 411 (;; SBCL introduces explicit keyword argument checking into 412 ;; the effective method. Since we do our own checking, we 413 ;; can safely disable it. However, we touch the relevant 414 ;; variables to prevent unused variable warnings. 416 (sb-pcl::check-applicable-keywords (&rest args) 417 (declare (ignore args)) 418 `(progn sb-pcl::.valid-keys. sb-pcl::.keyargs-start. (values))) 419 ;; SBCL introduces a magic form to report when there are no 420 ;; primary methods. The problem is that this form contains a 421 ;; reference to the literal generic function, which is not an 422 ;; externalizable object. Our solution is to replace it with 423 ;; something portable. 425 (sb-pcl::no-primary-method (&rest args) 426 (declare (ignore args)) 427 `(apply #'no-primary-method .gf. ,@',(lambda-list-apply-arguments lambda-list)))) 428 ,(wrap-in-call-method-macrolet 433 (defun wrap-in-call-method-macrolet (form generic-function lambda-list) 434 `(macrolet ((call-method (method &optional next-methods) 440 (sb-mop:generic-function-method-class generic-function))))) 441 ,(wrap-in-reinitialize-arguments form lambda-list))) 443 (defun wrap-in-reinitialize-arguments (form lambda-list) 444 (let ((anonymized-lambda-list 445 (anonymize-ordinary-lambda-list lambda-list))) 446 `(flet ((reinitialize-arguments ,anonymized-lambda-list 448 (lambda (place value) 449 `(setf ,place ,value)) 450 (lambda-list-variables lambda-list) 451 (lambda-list-variables anonymized-lambda-list)))) 452 (declare (ignorable #'reinitialize-arguments)) 453 (declare (inline reinitialize-arguments)) 456 (defun expand-call-method (method next-methods lambda-list method-class) 457 (wrap-in-next-methods 458 (call-fast-method-lambda 459 (coerce-to-fast-method method lambda-list method-class) 465 (defun coerce-to-fast-method (method lambda-list method-class) 466 (cond ((typep method 'fast-method) 469 (eql (car method) 'make-method) 470 (null (cddr method))) 471 (make-instance method-class 472 :lambda-list lambda-list 473 :specializers (make-list (length (parse-ordinary-lambda-list lambda-list)) 474 :initial-element (find-class 't)) 478 `(lambda ,lambda-list 479 (declare (ignorable ,@(lambda-list-variables lambda-list))) 482 (error "Cannot turn ~S into an inlineable method." 485 (defun wrap-in-next-methods (form next-methods lambda-list method-class) 486 (if (null next-methods) 487 `(flet ((next-method-p () nil) 492 (class-prototype (find-class ',method-class)) 493 ,@(lambda-list-apply-arguments lambda-list)))) 494 (declare (ignorable #'next-method-p #'call-next-method)) 496 (wrap-in-next-methods 497 `(flet ((next-method-p () t) 498 (call-next-method (&rest args) 500 (apply #'reinitialize-arguments args)) 501 (call-method ,(first next-methods) ,(rest next-methods)))) 502 (declare (ignorable #'next-method-p #'call-next-method)) 508 (defun call-fast-method-lambda (method lambda-list) 509 (multiple-value-bind (g-required g-optional g-rest-var g-keyword) 510 (parse-ordinary-lambda-list lambda-list) 511 (multiple-value-bind (m-required m-optional m-rest-var m-keyword) 512 (parse-ordinary-lambda-list (sb-mop:method-lambda-list method)) 513 ;; Assert that the method has arguments that are congruent to those 514 ;; of the corresponding generic function. 515 (assert (or (= (length g-required) 516 (length m-required)))) 517 (assert (= (length g-optional) 518 (length m-optional))) 519 (when (null g-rest-var) 520 (assert (null m-rest-var))) 522 ,(fast-method-lambda method) 523 ;; Required arguments. 524 ,@(mapcar #'required-info-variable g-required) 525 ;; Optional arguments. 526 ,@(loop for g-info in g-optional 527 for m-info in m-optional 529 (if (null (optional-info-suppliedp g-info)) 530 `(,(optional-info-variable g-info)) 532 `(if ,(optional-info-suppliedp g-info) 533 ,(optional-info-variable g-info) 534 ,(optional-info-initform m-info)))) 535 (if (null (optional-info-suppliedp m-info)) 537 `(,value ,(optional-info-suppliedp g-info)))))) 538 ;; The rest argument. 539 ,@(if (null m-rest-var) 542 ;; Keyword arguments. 543 ,@(loop for m-info in m-keyword 544 for g-info = (find (keyword-info-keyword m-info) g-keyword 545 :key #'keyword-info-keyword) 547 (if (null (keyword-info-suppliedp g-info)) 548 `(,(keyword-info-variable g-info)) 550 `(if ,(keyword-info-suppliedp g-info) 551 ,(keyword-info-variable g-info) 552 ,(keyword-info-initform m-info)))) 553 (if (null (keyword-info-suppliedp m-info)) 555 `(,value ,(keyword-info-suppliedp g-info)))))))))) 557 ;;; generic functions 558 (defgeneric optimize-function-call (generic-function static-call-signature)) 560 ;; may need to change this to conform with sb-pcl.. 561 (defgeneric no-primary-method (generic-function &rest arguments) 562 (:method ((generic-function generic-function) &rest arguments) 563 (error "~@<No primary method for call to the generic function ~S with ~ 565 generic-function arguments))) 568 (defclass fast-method (potentially-sealable-standard-method) 571 :reader fast-method-lambda 572 :initform (required-argument '.lambda.)))) 574 (defmethod validate-method-property 575 ((method fast-method) (property (eql 'inlineable))) 578 (defmethod make-method-lambda :around 579 ((gf sealable-standard-generic-function) 580 (fast-method fast-method) 583 (multiple-value-bind (method-lambda initargs) 589 (make-fast-method-lambda gf fast-method lambda environment) 592 ;; utility for the function below 593 (defun block-name (function-name) 594 (etypecase function-name 595 ((and symbol (not null)) function-name) 596 ((cons (eql setf) (cons symbol null)) (second function-name)))) 598 (defun make-fast-method-lambda 599 (generic-function method lambda environment) 600 (declare (ignore method)) 601 (destructuring-bind (lambda-symbol lambda-list &rest body) lambda 602 (assert (eql lambda-symbol 'lambda)) 603 (multiple-value-bind (required optional rest-var keyword allow-other-keys-p auxiliary) 604 (parse-ordinary-lambda-list lambda-list) 605 (multiple-value-bind (forms declarations) 607 (let ((partially-flattened-lambda-list 608 `(,@(lambda-list-variables 609 (unparse-ordinary-lambda-list 610 required optional rest-var keyword allow-other-keys-p '())) 611 ,@(unparse-ordinary-lambda-list '() '() nil '() nil auxiliary)))) 613 `(lambda ,partially-flattened-lambda-list 614 (declare (ignorable ,@(mapcar #'required-info-variable required))) 616 (block ,(block-name (sb-mop:generic-function-name generic-function)) 620 (defclass fast-generic-function (sealable-standard-generic-function) 621 ((%full-effective-method-cache :initform '() :accessor full-effective-method-cache) 622 (%flat-effective-method-cache :initform '() :accessor flat-effective-method-cache)) 624 :method-class (find-class 'fast-method)) 625 (:metaclass sb-mop:funcallable-standard-class)) 627 (defmethod compute-effective-method-function 628 ((fgf fast-generic-function) effective-method options) 630 (anonymize-ordinary-lambda-list 631 ;; Unfortunately, we don't know the list of applicable methods 632 ;; anymore at this stage. So instead, we consider all methods 634 (compute-effective-method-lambda-list fgf (sb-mop:generic-function-methods fgf))))) 637 `(lambda ,lambda-list 638 ,(expand-effective-method-body effective-method fgf lambda-list))))) 640 ;;; optimize-function-call 641 (defmethod optimize-function-call :around 642 ((fast-generic-function fast-generic-function) 643 (static-call-signature static-call-signature)) 646 (defmethod optimize-function-call 647 ((fast-generic-function fast-generic-function) 648 (static-call-signature static-call-signature)) 649 (let ((applicable-methods 650 (compute-applicable-methods 651 fast-generic-function 652 (static-call-signature-prototypes static-call-signature)))) 653 (cond (;; Inline the entire effective method. 654 (every #'inlineable-method-p applicable-methods) 655 (effective-method-lambda fast-generic-function static-call-signature nil)) 656 ;; Inline only the optional/keyword parsing step. 657 ((and (externalizable-object-p static-call-signature) 658 (intersection (sb-mop:generic-function-lambda-list fast-generic-function) 659 '(&optional &key &rest))) 661 (anonymize-ordinary-lambda-list 662 (compute-effective-method-lambda-list 663 fast-generic-function applicable-methods)))) 664 `(lambda ,lambda-list 668 (lookup-flat-effective-method 669 #',(sb-mop:generic-function-name fast-generic-function) 670 ',static-call-signature))) 671 ,@(lambda-list-variables lambda-list))))) 672 ;; Eliminate the dispatch function. 673 ((externalizable-object-p static-call-signature) 674 `(lambda (&rest args) 678 (lookup-full-effective-method 679 #',(sb-mop:generic-function-name fast-generic-function) 680 ',static-call-signature))) 685 (defun inlineable-method-p (method) 686 (member 'inlineable (method-properties method))) 688 (defun effective-method-lambda 689 (generic-function static-call-signature flatten-arguments) 690 (let* ((applicable-methods 691 (compute-applicable-methods 693 (static-call-signature-prototypes static-call-signature))) 694 (effective-method-lambda-list 695 (compute-effective-method-lambda-list 696 generic-function applicable-methods)) 697 (anonymized-lambda-list 698 (anonymize-ordinary-lambda-list effective-method-lambda-list))) 699 `(lambda ,(if flatten-arguments 700 (lambda-list-variables anonymized-lambda-list) 701 anonymized-lambda-list) 702 (declare (optimize (safety 0))) 703 ,@(loop for type in (static-call-signature-types static-call-signature) 704 for argument in anonymized-lambda-list 705 collect `(declare (ignorable ,argument)) 706 collect `(declare (type ,type ,argument))) 707 (locally (declare (optimize (safety 1))) 708 ,(expand-effective-method-body 709 (sb-mop:compute-effective-method 711 (sb-mop:generic-function-method-combination generic-function) 714 anonymized-lambda-list))))) 716 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 718 ;;; Computing the Effective Method Lambda List 720 (defun merge-required-infos (g-required m-requireds) 721 (dolist (m-required m-requireds g-required) 722 (assert (= (length m-required) 723 (length g-required))))) 725 (defun merge-optional-infos (g-optional m-optionals) 726 (let ((n (length g-optional))) 727 (dolist (m-optional m-optionals) 728 (assert (= (length m-optional) n))) 730 (loop for g-info in g-optional 731 for m-infos in (apply #'mapcar #'list m-optionals) 733 ;; Now we have two cases - the one is that at least one method 734 ;; cares about the suppliedp flag, the other one is that no 735 ;; method cares. Even if a method doesn't reference the 736 ;; suppliedp flag itself, it may still need it to decide whether 737 ;; to supply its initform or not. Because of this, the suppliedp 738 ;; parameter can only be discarded globally when the initforms of 739 ;; all methods are constant and equal. 740 (let ((global-initform (optional-info-initform (first m-infos))) 741 (no-one-cares (not (optional-info-suppliedp (first m-infos))))) 742 (dolist (m-info m-infos) 743 (with-accessors ((variable optional-info-variable) 744 (initform optional-info-initform) 745 (suppliedp optional-info-suppliedp)) 747 (unless (and (constantp initform) 748 (equal initform global-initform) 750 (setf no-one-cares nil)))) 752 (make-instance 'optional-info 753 :variable (optional-info-variable g-info) 754 :initform global-initform) 755 (make-instance 'optional-info 756 :variable (optional-info-variable g-info) 758 :suppliedp (optional-info-suppliedp g-info)))))))) 760 (defun merge-keyword-infos (g-keyword m-keywords) 761 ;; First we assemble an alist whose keys are keywords and whose values 762 ;; are all method keyword info objects that read this keyword. 764 (dolist (g-info g-keyword) 765 (pushnew (list (keyword-info-keyword g-info)) alist)) 766 (dolist (m-keyword m-keywords) 767 (dolist (m-info m-keyword) 768 (let* ((key (keyword-info-keyword m-info)) 769 (entry (assoc key alist))) 771 (push m-info (cdr entry)) 772 (push (list key m-info) alist))))) 773 (loop for (key . m-infos) in alist 775 ;; Merging keyword info objects is handled just like in the case 776 ;; of optional info objects above. 777 (let ((global-initform (keyword-info-initform (first m-infos))) 778 (no-one-cares (not (keyword-info-suppliedp (first m-infos)))) 779 ;; Not actually g-info, but we need some place to grab a 780 ;; variable name form. 781 (g-info (or (find key g-keyword :key #'keyword-info-keyword) 783 (dolist (m-info m-infos) 784 (with-accessors ((initform keyword-info-initform) 785 (suppliedp keyword-info-suppliedp)) 787 (unless (and (constantp initform) 788 (equal initform global-initform) 790 (setf no-one-cares nil)))) 792 (make-instance 'keyword-info 794 :variable (keyword-info-variable g-info) 795 :initform global-initform) 796 (make-instance 'keyword-info 798 :variable (keyword-info-variable g-info) 800 :suppliedp (or (keyword-info-suppliedp g-info) 801 (gensymify "SUPPLIEDP")))))))) 803 (defun merge-allow-other-keys (g-allow-other-keys m-allow-other-keys-list) 805 (lambda (a b) (or a b)) 806 m-allow-other-keys-list 807 :initial-value g-allow-other-keys)) 809 (defun compute-effective-method-lambda-list (generic-function applicable-methods) 810 (multiple-value-bind (required optional rest-var keyword allow-other-keys) 811 (parse-ordinary-lambda-list (sb-mop:generic-function-lambda-list generic-function)) 816 (parse-ordinary-lambda-list 817 (sb-mop:method-lambda-list method)))) 818 applicable-methods))) 819 (unparse-ordinary-lambda-list 820 (merge-required-infos required (mapcar #'first method-parses)) 821 (merge-optional-infos optional (mapcar #'second method-parses)) 823 (merge-keyword-infos keyword (mapcar #'fourth method-parses)) 824 (merge-allow-other-keys allow-other-keys (mapcar #'fifth method-parses)) 827 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 829 ;;; Effective Method Lookup 831 (declaim (ftype (function * function) lookup-full-effective-method)) 832 (declaim (ftype (function * function) lookup-flat-effective-method)) 834 (defun lookup-full-effective-method 835 (generic-function static-call-signature) 836 (with-accessors ((alist full-effective-method-cache)) generic-function 837 (let* ((key (static-call-signature-types static-call-signature)) 838 (entry (assoc key alist :test #'equal))) 841 (let ((fn (compile nil (effective-method-lambda 843 static-call-signature 845 (push (cons key fn) alist) 848 (defun lookup-flat-effective-method 849 (generic-function static-call-signature) 850 (with-accessors ((alist flat-effective-method-cache)) generic-function 851 (let* ((key (static-call-signature-types static-call-signature)) 852 (entry (assoc key alist :test #'equal))) 855 (let ((fn (compile nil (effective-method-lambda 857 static-call-signature 859 (push (cons key fn) alist) 862 (defmethod seal-domain :after 863 ((fast-generic-function fast-generic-function) 865 (let ((name (sb-mop:generic-function-name fast-generic-function))) 866 ;; Ensure that the function is known. 867 (unless (sb-c::info :function :info name) 868 (compile nil (eval `(sb-c:defknown ,name * * ())))) 869 ;; Create an IR1-transform for each static call signature. 870 (dolist (static-call-signature (compute-static-call-signatures fast-generic-function domain)) 871 (with-accessors ((types static-call-signature-types) 872 (prototypes static-call-signature-prototypes)) 873 static-call-signature 875 `(sb-c:deftransform ,name ((&rest args) (,@types &rest *)) 876 (or (optimize-function-call #',name ',static-call-signature) 877 (sb-c::give-up-ir1-transform))))))))