Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
79 lines
2.8 KiB
Plaintext
79 lines
2.8 KiB
Plaintext
;; Inline-cache tests — verify the per-call-site IC slot fires on hot
|
|
;; sends and is invalidated by class-table mutations.
|
|
|
|
(set! st-test-pass 0)
|
|
(set! st-test-fail 0)
|
|
(set! st-test-fails (list))
|
|
|
|
(st-bootstrap-classes!)
|
|
(define ev (fn (src) (smalltalk-eval src)))
|
|
(define evp (fn (src) (smalltalk-eval-program src)))
|
|
|
|
;; ── 1. Counters exist ──
|
|
(st-test "stats has :hits" (has-key? (st-ic-stats) :hits) true)
|
|
(st-test "stats has :misses" (has-key? (st-ic-stats) :misses) true)
|
|
(st-test "stats has :gen" (has-key? (st-ic-stats) :gen) true)
|
|
|
|
;; ── 2. Repeated send to user method hits the IC ──
|
|
(st-class-define! "Pinger" "Object" (list))
|
|
(st-class-add-method! "Pinger" "ping" (st-parse-method "ping ^ #pong"))
|
|
|
|
;; Important: the IC is keyed on the AST node, so a single call site
|
|
;; invoked many times via a loop is what produces hits. Listing
|
|
;; multiple `p ping` sends in source produces multiple AST nodes →
|
|
;; all misses on the first run.
|
|
(st-ic-reset-stats!)
|
|
(evp "| p | p := Pinger new.
|
|
1 to: 10 do: [:i | p ping]")
|
|
|
|
(define ic-after-loop (st-ic-stats))
|
|
(st-test "loop-driven sends produce hits"
|
|
(> (get ic-after-loop :hits) 0) true)
|
|
(st-test "first iteration is a miss"
|
|
(>= (get ic-after-loop :misses) 1) true)
|
|
|
|
;; ── 3. Different receiver class causes a miss ──
|
|
(st-class-define! "Cooer" "Object" (list))
|
|
(st-class-add-method! "Cooer" "ping" (st-parse-method "ping ^ #coo"))
|
|
|
|
(st-ic-reset-stats!)
|
|
(evp "| p c |
|
|
p := Pinger new.
|
|
c := Cooer new.
|
|
^ {p ping. c ping. p ping. c ping}")
|
|
;; First p ping → miss. c ping with same call site → miss (class changed).
|
|
;; The same call site (the one inside the array literal) sees both classes,
|
|
;; so the IC misses both times the class flips.
|
|
(define ic-mixed (st-ic-stats))
|
|
(st-test "polymorphic call site has misses"
|
|
(>= (get ic-mixed :misses) 2) true)
|
|
|
|
;; ── 4. Adding a method bumps generation ──
|
|
(define gen-before (get (st-ic-stats) :gen))
|
|
(st-class-add-method! "Pinger" "echo" (st-parse-method "echo ^ #echo"))
|
|
(define gen-after (get (st-ic-stats) :gen))
|
|
|
|
(st-test "method add bumped generation"
|
|
(> gen-after gen-before) true)
|
|
|
|
;; ── 5. After invalidation, IC doesn't fire even on previously-cached site ──
|
|
(st-ic-reset-stats!)
|
|
(evp "| p | p := Pinger new. ^ p ping") ;; warm
|
|
(evp "| p | p := Pinger new. ^ p ping") ;; should hit
|
|
(st-class-add-method! "Pinger" "ping" (st-parse-method "ping ^ #newPong"))
|
|
(evp "| p | p := Pinger new. ^ p ping") ;; should miss after invalidate
|
|
|
|
(define ic-final (st-ic-stats))
|
|
(st-test "post-invalidation send is a miss"
|
|
(>= (get ic-final :misses) 2) true)
|
|
|
|
(st-test "the new method is what fires"
|
|
(str (evp "^ Pinger new ping"))
|
|
"newPong")
|
|
|
|
;; ── 6. Default IC generation starts at >= 0 ──
|
|
(st-test "generation is non-negative"
|
|
(>= (get (st-ic-stats) :gen) 0) true)
|
|
|
|
(list st-test-pass st-test-fail)
|