Changeset 12042
- Timestamp:
- 07/13/09 14:10:50 (14 years ago)
- Location:
- trunk/abcl/src/org/armedbear/lisp
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/abcl/src/org/armedbear/lisp/StandardGenericFunction.java
r11754 r12042 446 446 throws ConditionThrowable 447 447 { 448 checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION] = second; 448 checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION] 449 = second; 449 450 return second; 450 451 } … … 458 459 public LispObject execute(LispObject arg) throws ConditionThrowable 459 460 { 460 return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER]; 461 return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass 462 .SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER]; 461 463 } 462 464 }; … … 470 472 throws ConditionThrowable 471 473 { 472 checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER] = second; 474 checkStandardGenericFunction(first) 475 .slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER] = second; 473 476 return second; 474 477 } … … 482 485 public LispObject execute(LispObject arg) throws ConditionThrowable 483 486 { 484 return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE]; 487 return checkStandardGenericFunction(arg) 488 .slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE]; 485 489 } 486 490 }; … … 494 498 throws ConditionThrowable 495 499 { 496 checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE] = second; 500 checkStandardGenericFunction(first) 501 .slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE] = second; 497 502 return second; 498 503 } … … 518 523 throws ConditionThrowable 519 524 { 520 checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION] = second; 525 checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION] 526 = second; 521 527 return second; 522 528 } … … 551 557 for (int i = gf.numberOfRequiredArgs; i-- > 0;) 552 558 { 553 array[i] = args.car().classOf();559 array[i] = gf.getArgSpecialization(args.car()); 554 560 args = args.cdr(); 555 561 } 556 CacheEntry classes = new CacheEntry(array);562 CacheEntry specializations = new CacheEntry(array); 557 563 HashMap<CacheEntry,LispObject> ht = gf.cache; 558 564 if (ht == null) 559 565 ht = gf.cache = new HashMap<CacheEntry,LispObject>(); 560 ht.put( classes, third);566 ht.put(specializations, third); 561 567 return third; 562 568 } … … 576 582 for (int i = gf.numberOfRequiredArgs; i-- > 0;) 577 583 { 578 array[i] = args.car().classOf();584 array[i] = gf.getArgSpecialization(args.car()); 579 585 args = args.cdr(); 580 586 } 581 CacheEntry classes = new CacheEntry(array);587 CacheEntry specializations = new CacheEntry(array); 582 588 HashMap<CacheEntry,LispObject> ht = gf.cache; 583 589 if (ht == null) 584 590 return NIL; 585 LispObject emf = (LispObject) ht.get( classes);591 LispObject emf = (LispObject) ht.get(specializations); 586 592 return emf != null ? emf : NIL; 593 } 594 }; 595 596 /** 597 * Returns an object representing generic function 598 * argument <tt>arg</tt> in a <tt>CacheEntry</tt> 599 * 600 * <p>In the simplest case, when this generic function 601 * does not have EQL specialized methos, and therefore 602 * only argument types are relevant for choosing 603 * applicable methods, the value returned is the 604 * class of <tt>arg</tt> 605 * 606 * <p>If the function has EQL specialized methods: 607 * - if <tt>arg</tt> is EQL to some of the EQL-specializers, 608 * a special object representing equality to that specializer 609 * is returned. 610 * - otherwise class of the <tt>arg</tt> is returned. 611 * 612 * <p>Note that we do not consider argument position, when 613 * calculating arg specialization. In rare cases (when 614 * one argument is eql-specialized to a symbol specifying 615 * class of another argument) this may result in redundant cache 616 * entries caching the same method. But the method cached is anyway 617 * correct for the arguments (because in case of cache miss, correct method 618 * is calculated by other code, which does not rely on getArgSpecialization; 619 * and because EQL is true only for objects of the same type, which guaranties 620 * that if a type-specialized methods was chached by eql-specialization, 621 * all the cache hits into this records will be from args of the conforming 622 * type). 623 * 624 * <p>Consider: 625 * <pre><tt> 626 * (defgeneric f (a b)) 627 * 628 * (defmethod f (a (b (eql 'symbol))) 629 * "T (EQL 'SYMBOL)") 630 * 631 * (defmethod f ((a symbol) (b (eql 'symbol))) 632 * "SYMBOL (EQL 'SYMBOL)") 633 * 634 * (f 12 'symbol) 635 * => "T (EQL 'SYMBOL)" 636 * 637 * (f 'twelve 'symbol) 638 * => "SYMBOL (EQL 'SYMBOL)" 639 * 640 * (f 'symbol 'symbol) 641 * => "SYMBOL (EQL 'SYMBOL)" 642 * 643 * </tt></pre> 644 * 645 * After the two above calls <tt>cache</tt> will contain tree keys: 646 * <pre> 647 * { class FIXNUM, EqlSpecialization('SYMBOL) } 648 * { class SYMBOL, EqlSpecialization('SYMBOL) } 649 * { EqlSpecialization('SYMBOL), EqlSpecialization('SYMBOL) }. 650 * </pre> 651 */ 652 private LispObject getArgSpecialization(LispObject arg) 653 { 654 for (EqlSpecialization eqlSpecialization : eqlSpecializations) 655 { 656 if (eqlSpecialization.eqlTo.eql(arg)) 657 return eqlSpecialization; 658 } 659 return arg.classOf(); 660 } 661 662 // ### %get-arg-specialization 663 private static final Primitive _GET_ARG_SPECIALIZATION = 664 new Primitive("%get-arg-specialization", PACKAGE_SYS, true, "generic-function arg") 665 { 666 @Override 667 public LispObject execute(LispObject first, LispObject second) 668 throws ConditionThrowable 669 { 670 final StandardGenericFunction gf = checkStandardGenericFunction(first); 671 return gf.getArgSpecialization(second); 587 672 } 588 673 }; … … 667 752 } 668 753 } 754 755 private EqlSpecialization eqlSpecializations[] = new EqlSpecialization[0]; 756 757 // ### %init-eql-specializations 758 private static final Primitive _INIT_EQL_SPECIALIZATIONS 759 = new Primitive("%init-eql-specializations", PACKAGE_SYS, true, 760 "generic-function eql-specilizer-objects-list") 761 { 762 @Override 763 public LispObject execute(LispObject first, LispObject second) 764 throws ConditionThrowable 765 { 766 final StandardGenericFunction gf = checkStandardGenericFunction(first); 767 LispObject eqlSpecializerObjects = second; 768 gf.eqlSpecializations = new EqlSpecialization[eqlSpecializerObjects.length()]; 769 for (int i = 0; i < gf.eqlSpecializations.length; i++) { 770 gf.eqlSpecializations[i] = new EqlSpecialization(eqlSpecializerObjects.car()); 771 eqlSpecializerObjects = eqlSpecializerObjects.cdr(); 772 } 773 return NIL; 774 } 775 }; 776 777 private static class EqlSpecialization extends LispObject 778 { 779 public LispObject eqlTo; 780 781 public EqlSpecialization(LispObject eqlTo) 782 { 783 this.eqlTo = eqlTo; 784 } 785 } 669 786 670 787 public static final StandardGenericFunction checkStandardGenericFunction(LispObject obj) 671 788 throws ConditionThrowable 672 789 { 673 674 675 676 677 790 if (obj instanceof StandardGenericFunction) 791 return (StandardGenericFunction) obj; 792 return (StandardGenericFunction) // Not reached. 793 type_error(obj, Symbol.STANDARD_GENERIC_FUNCTION); 794 } 678 795 } -
trunk/abcl/src/org/armedbear/lisp/clos.lisp
r11992 r12042 858 858 (apply gf args)) 859 859 860 (defun collect-eql-specializer-objects (generic-function) 861 (let ((result nil)) 862 (dolist (method (generic-function-methods generic-function)) 863 (dolist (specializer (%method-specializers method)) 864 (when (typep specializer 'eql-specializer) 865 (pushnew (eql-specializer-object specializer) 866 result 867 :test 'eql)))) 868 result)) 869 860 870 (defun finalize-generic-function (gf) 861 871 (%finalize-generic-function gf) 862 872 (setf (classes-to-emf-table gf) (make-hash-table :test #'equal)) 873 (%init-eql-specializations gf (collect-eql-specializer-objects gf)) 863 874 (set-funcallable-instance-function 864 875 gf … … 1185 1196 method))) 1186 1197 1187 (defun methods-contain-eql-specializer-p (methods)1188 (dolist (method methods nil)1189 (when (dolist (spec (%method-specializers method) nil)1190 (when (eql-specializer-p spec) (return t)))1191 (return t))))1192 1193 1198 (defun fast-callable-p (gf) 1194 1199 (and (eq (generic-function-method-combination gf) 'standard) … … 1206 1211 (defun std-compute-discriminating-function (gf) 1207 1212 (let ((code 1208 (cond ((methods-contain-eql-specializer-p (generic-function-methods gf)) 1209 (make-closure `(lambda (&rest args) 1210 (slow-method-lookup ,gf args)) 1211 nil)) 1212 ((and (= (length (generic-function-methods gf)) 1) 1213 (cond ((and (= (length (generic-function-methods gf)) 1) 1213 1214 (typep (car (generic-function-methods gf)) 'standard-reader-method)) 1214 1215 ;; (sys::%format t "standard reader function ~S~%" (generic-function-name gf)) … … 1246 1247 (= (length (generic-function-methods gf)) 1)) 1247 1248 (let* ((method (%car (generic-function-methods gf))) 1248 ( class(car (%method-specializers method)))1249 (specializer (car (%method-specializers method))) 1249 1250 (function (or (%method-fast-function method) 1250 1251 (%method-function method)))) 1251 `(lambda (arg) 1252 (declare (optimize speed)) 1253 (unless (simple-typep arg ,class) 1254 ;; FIXME no applicable method 1255 (error 'simple-type-error 1256 :datum arg 1257 :expected-type ,class)) 1258 (funcall ,function arg)))) 1252 (if (eql-specializer-p specializer) 1253 (let ((specializer-object (eql-specializer-object specializer))) 1254 `(lambda (arg) 1255 (declare (optimize speed)) 1256 (if (eql arg ',specializer-object) 1257 (funcall ,function arg) 1258 (no-applicable-method ,gf (list arg))))) 1259 `(lambda (arg) 1260 (declare (optimize speed)) 1261 (unless (simple-typep arg ,specializer) 1262 ;; FIXME no applicable method 1263 (error 'simple-type-error 1264 :datum arg 1265 :expected-type ,specializer)) 1266 (funcall ,function arg))))) 1259 1267 (t 1260 1268 `(lambda (arg) 1261 1269 (declare (optimize speed)) 1262 (let* (( class (class-of arg))1263 (emfun (or (gethash1 class,emf-table)1264 (slow-method-lookup-1 ,gf class))))1270 (let* ((specialization (%get-arg-specialization ,gf arg)) 1271 (emfun (or (gethash1 specialization ,emf-table) 1272 (slow-method-lookup-1 ,gf arg specialization)))) 1265 1273 (if emfun 1266 1274 (funcall emfun (list arg)) … … 1276 1284 (if emfun 1277 1285 (funcall emfun args) 1278 1286 (slow-method-lookup ,gf args)))))) 1279 1287 ((= number-required 2) 1280 1288 (if exact … … 1369 1377 (return nil))))) 1370 1378 1371 (defun %compute-applicable-methods-using-classes (gf required-classes)1372 (let ((methods '()))1373 (dolist (method (generic-function-methods gf))1374 (when (method-applicable-p-using-classes method required-classes)1375 (push method methods)))1376 (if (or (null methods) (null (%cdr methods)))1377 methods1378 (sort methods1379 (if (eq (class-of gf) (find-class 'standard-generic-function))1380 #'(lambda (m1 m2)1381 (std-method-more-specific-p m1 m2 required-classes1382 (generic-function-argument-precedence-order gf)))1383 #'(lambda (m1 m2)1384 (method-more-specific-p gf m1 m2 required-classes)))))))1385 1386 1379 (defun slow-method-lookup (gf args) 1387 1380 (let ((applicable-methods (%compute-applicable-methods gf args))) … … 1395 1388 (apply #'no-applicable-method gf args)))) 1396 1389 1397 (defun slow-method-lookup-1 (gf class)1398 (let ((applicable-methods (%compute-applicable-methods -using-classes gf (list class))))1390 (defun slow-method-lookup-1 (gf arg arg-specialization) 1391 (let ((applicable-methods (%compute-applicable-methods gf (list arg)))) 1399 1392 (if applicable-methods 1400 1393 (let ((emfun (funcall (if (eq (class-of gf) (find-class 'standard-generic-function)) … … 1403 1396 gf applicable-methods))) 1404 1397 (when emfun 1405 (setf (gethash class(classes-to-emf-table gf)) emfun))1398 (setf (gethash arg-specialization (classes-to-emf-table gf)) emfun)) 1406 1399 emfun)))) 1407 1400
Note: See TracChangeset
for help on using the changeset viewer.