dispatch.scm 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. ;;;; Copyright (C) 1999, 2000, 2001, 2003, 2006 Free Software Foundation, Inc.
  2. ;;;;
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 2.1 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;;;
  17. (define-module (oop goops dispatch)
  18. :use-module (oop goops)
  19. :use-module (oop goops util)
  20. :use-module (oop goops compile)
  21. :export (memoize-method!)
  22. :no-backtrace
  23. )
  24. ;;;
  25. ;;; This file implements method memoization. It will finally be
  26. ;;; implemented on C level in order to obtain fast generic function
  27. ;;; application also during the first pass through the code.
  28. ;;;
  29. ;;;
  30. ;;; Constants
  31. ;;;
  32. (define hashsets 8)
  33. (define hashset-index 6)
  34. (define hash-threshold 3)
  35. (define initial-hash-size 4) ;must be a power of 2 and >= hash-threshold
  36. (define initial-hash-size-1 (- initial-hash-size 1))
  37. (define the-list-of-no-method '(no-method))
  38. ;;;
  39. ;;; Method cache
  40. ;;;
  41. ;; (#@dispatch args N-SPECIALIZED #((TYPE1 ... ENV FORMALS FORM1 ...) ...) GF)
  42. ;; (#@dispatch args N-SPECIALIZED HASHSET MASK
  43. ;; #((TYPE1 ... ENV FORMALS FORM1 ...) ...)
  44. ;; GF)
  45. ;;; Representation
  46. ;; non-hashed form
  47. (define method-cache-entries cadddr)
  48. (define (set-method-cache-entries! mcache entries)
  49. (set-car! (cdddr mcache) entries))
  50. (define (method-cache-n-methods exp)
  51. (n-cache-methods (method-cache-entries exp)))
  52. (define (method-cache-methods exp)
  53. (cache-methods (method-cache-entries exp)))
  54. ;; hashed form
  55. (define (set-hashed-method-cache-hashset! exp hashset)
  56. (set-car! (cdddr exp) hashset))
  57. (define (set-hashed-method-cache-mask! exp mask)
  58. (set-car! (cddddr exp) mask))
  59. (define (hashed-method-cache-entries exp)
  60. (list-ref exp 5))
  61. (define (set-hashed-method-cache-entries! exp entries)
  62. (set-car! (list-cdr-ref exp 5) entries))
  63. ;; either form
  64. (define (method-cache-generic-function exp)
  65. (list-ref exp (if (method-cache-hashed? exp) 6 4)))
  66. ;;; Predicates
  67. (define (method-cache-hashed? x)
  68. (integer? (cadddr x)))
  69. (define max-non-hashed-index (- hash-threshold 2))
  70. (define (passed-hash-threshold? exp)
  71. (and (> (vector-length (method-cache-entries exp)) max-non-hashed-index)
  72. (struct? (car (vector-ref (method-cache-entries exp)
  73. max-non-hashed-index)))))
  74. ;;; Converting a method cache to hashed form
  75. (define (method-cache->hashed! exp)
  76. (set-cdr! (cddr exp) (cons 0 (cons initial-hash-size-1 (cdddr exp))))
  77. exp)
  78. ;;;
  79. ;;; Cache entries
  80. ;;;
  81. (define (n-cache-methods entries)
  82. (do ((i (- (vector-length entries) 1) (- i 1)))
  83. ((or (< i 0) (struct? (car (vector-ref entries i))))
  84. (+ i 1))))
  85. (define (cache-methods entries)
  86. (do ((i (- (vector-length entries) 1) (- i 1))
  87. (methods '() (let ((entry (vector-ref entries i)))
  88. (if (struct? (car entry))
  89. (cons entry methods)
  90. methods))))
  91. ((< i 0) methods)))
  92. ;;;
  93. ;;; Method insertion
  94. ;;;
  95. (define (method-cache-insert! exp entry)
  96. (let* ((entries (method-cache-entries exp))
  97. (n (n-cache-methods entries)))
  98. (if (>= n (vector-length entries))
  99. ;; grow cache
  100. (let ((new-entries (make-vector (* 2 (vector-length entries))
  101. the-list-of-no-method)))
  102. (do ((i 0 (+ i 1)))
  103. ((= i n))
  104. (vector-set! new-entries i (vector-ref entries i)))
  105. (vector-set! new-entries n entry)
  106. (set-method-cache-entries! exp new-entries))
  107. (vector-set! entries n entry))))
  108. (define (hashed-method-cache-insert! exp entry)
  109. (let* ((cache (hashed-method-cache-entries exp))
  110. (size (vector-length cache)))
  111. (let* ((entries (cons entry (cache-methods cache)))
  112. (size (if (<= (length entries) size)
  113. size
  114. ;; larger size required
  115. (let ((new-size (* 2 size)))
  116. (set-hashed-method-cache-mask! exp (- new-size 1))
  117. new-size)))
  118. (min-misses size)
  119. (best #f))
  120. (do ((hashset 0 (+ 1 hashset)))
  121. ((= hashset hashsets))
  122. (let* ((test-cache (make-vector size the-list-of-no-method))
  123. (misses (cache-try-hash! min-misses hashset test-cache entries)))
  124. (cond ((zero? misses)
  125. (set! min-misses 0)
  126. (set! best hashset)
  127. (set! cache test-cache)
  128. (set! hashset (- hashsets 1)))
  129. ((< misses min-misses)
  130. (set! min-misses misses)
  131. (set! best hashset)
  132. (set! cache test-cache)))))
  133. (set-hashed-method-cache-hashset! exp best)
  134. (set-hashed-method-cache-entries! exp cache))))
  135. ;;;
  136. ;;; Caching
  137. ;;;
  138. (define (cache-hashval hashset entry)
  139. (let ((hashset-index (+ hashset-index hashset)))
  140. (do ((sum 0)
  141. (classes entry (cdr classes)))
  142. ((not (struct? (car classes))) sum)
  143. (set! sum (+ sum (struct-ref (car classes) hashset-index))))))
  144. (define (cache-try-hash! min-misses hashset cache entries)
  145. (let ((max-misses 0)
  146. (mask (- (vector-length cache) 1)))
  147. (catch 'misses
  148. (lambda ()
  149. (do ((ls entries (cdr ls))
  150. (misses 0 0))
  151. ((null? ls) max-misses)
  152. (do ((i (logand mask (cache-hashval hashset (car ls)))
  153. (logand mask (+ i 1))))
  154. ((not (struct? (car (vector-ref cache i))))
  155. (vector-set! cache i (car ls)))
  156. (set! misses (+ 1 misses))
  157. (if (>= misses min-misses)
  158. (throw 'misses misses)))
  159. (if (> misses max-misses)
  160. (set! max-misses misses))))
  161. (lambda (key misses)
  162. misses))))
  163. ;;;
  164. ;;; Memoization
  165. ;;;
  166. ;; Backward compatibility
  167. (if (not (defined? 'lookup-create-cmethod))
  168. (define (lookup-create-cmethod gf args)
  169. (no-applicable-method (car args) (cadr args))))
  170. (define (memoize-method! gf args exp)
  171. (if (not (slot-ref gf 'used-by))
  172. (slot-set! gf 'used-by '()))
  173. (let ((applicable ((if (eq? gf compute-applicable-methods)
  174. %compute-applicable-methods
  175. compute-applicable-methods)
  176. gf args)))
  177. (cond (applicable
  178. ;; *fixme* dispatch.scm needs rewriting Since the current
  179. ;; code mutates the method cache, we have to work on a
  180. ;; copy. Otherwise we might disturb another thread
  181. ;; currently dispatching on the cache. (No need to copy
  182. ;; the vector.)
  183. (let* ((new (list-copy exp))
  184. (res
  185. (cond ((method-cache-hashed? new)
  186. (method-cache-install! hashed-method-cache-insert!
  187. new args applicable))
  188. ((passed-hash-threshold? new)
  189. (method-cache-install! hashed-method-cache-insert!
  190. (method-cache->hashed! new)
  191. args
  192. applicable))
  193. (else
  194. (method-cache-install! method-cache-insert!
  195. new args applicable)))))
  196. (set-cdr! (cdr exp) (cddr new))
  197. res))
  198. ((null? args)
  199. (lookup-create-cmethod no-applicable-method (list gf '())))
  200. (else
  201. ;; Mutate arglist to fit no-applicable-method
  202. (set-cdr! args (list (cons (car args) (cdr args))))
  203. (set-car! args gf)
  204. (lookup-create-cmethod no-applicable-method args)))))
  205. (set-procedure-property! memoize-method! 'system-procedure #t)
  206. (define method-cache-install!
  207. (letrec ((first-n
  208. (lambda (ls n)
  209. (if (or (zero? n) (null? ls))
  210. '()
  211. (cons (car ls) (first-n (cdr ls) (- n 1)))))))
  212. (lambda (insert! exp args applicable)
  213. (let* ((specializers (method-specializers (car applicable)))
  214. (n-specializers
  215. (if (list? specializers)
  216. (length specializers)
  217. (+ 1 (slot-ref (method-cache-generic-function exp)
  218. 'n-specialized)))))
  219. (let* ((types (map class-of (first-n args n-specializers)))
  220. (entry+cmethod (compute-entry-with-cmethod applicable types)))
  221. (insert! exp (car entry+cmethod)) ; entry = types + cmethod
  222. (cdr entry+cmethod) ; cmethod
  223. )))))