1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Simplify and optimize slot access

* module/oop/goops.scm (fold-slot-slots): Add `slot-ref/raw' slot, which
  is what the slot-ref slot was.  Now the slot-ref slot checks that the
  slot is bound, if needed.
  (slot-definition-slot-ref/raw): Define.
  (make-slot): Adapt.  Also, effective slot definition slots have no
  initargs.
  (define-standard-accessor-method, bound-check-get, standard-get)
  (standard-set): Move definitions up.
  (allocate-slots): Adapt.  If the slot has an init thunk, we don't need
  to check that it's bound.
  (slot-ref, slot-set!, slot-bound?): Simplify.
  (class-slot-ref): Use the raw getter so that we can call
  `slot-unbound' with just the class.
  (compute-getter-method, compute-setter-method): Simplify to just use
  the slot-ref / slot-set! functions from the slot.
  (%initialize-object): Simplify.
This commit is contained in:
Andy Wingo 2015-01-23 14:55:35 +01:00
parent 193e2c52dc
commit 4bde3f04ea

View file

@ -208,6 +208,7 @@
(accessor #:init-keyword #:accessor #:init-value #f) (accessor #:init-keyword #:accessor #:init-value #f)
;; These last don't have #:init-keyword because they are meant to be ;; These last don't have #:init-keyword because they are meant to be
;; set by `allocate-slots', not in compute-effective-slot-definition. ;; set by `allocate-slots', not in compute-effective-slot-definition.
(slot-ref/raw #:init-value #f)
(slot-ref #:init-value #f) (slot-ref #:init-value #f)
(slot-set! #:init-value #f) (slot-set! #:init-value #f)
(index #:init-value #f) (index #:init-value #f)
@ -476,11 +477,14 @@ followed by its associated value. If @var{l} does not hold a value for
(define-slot-accessor slot-definition-accessor (define-slot-accessor slot-definition-accessor
"Return the accessor of the slot @var{obj}, or @code{#f}." "Return the accessor of the slot @var{obj}, or @code{#f}."
%slot-definition-accessor slot-index-accessor) %slot-definition-accessor slot-index-accessor)
(define-slot-accessor slot-definition-slot-ref/raw
"Return the raw slot-ref procedure of the slot @var{obj}."
%slot-definition-slot-ref/raw slot-index-slot-ref/raw)
(define-slot-accessor slot-definition-slot-ref (define-slot-accessor slot-definition-slot-ref
"Return the slot-ref procedure of the slot @var{obj}, or @code{#f}." "Return the slot-ref procedure of the slot @var{obj}."
%slot-definition-slot-ref slot-index-slot-ref) %slot-definition-slot-ref slot-index-slot-ref)
(define-slot-accessor slot-definition-slot-set! (define-slot-accessor slot-definition-slot-set!
"Return the slot-set! procedure of the slot @var{obj}, or @code{#f}." "Return the slot-set! procedure of the slot @var{obj}."
%slot-definition-slot-set! slot-index-slot-set!) %slot-definition-slot-set! slot-index-slot-set!)
(define-slot-accessor slot-definition-index (define-slot-accessor slot-definition-index
"Return the allocated struct offset of the slot @var{obj}, or @code{#f}." "Return the allocated struct offset of the slot @var{obj}, or @code{#f}."
@ -513,10 +517,11 @@ followed by its associated value. If @var{l} does not hold a value for
(init-slot slot-index-getter #:getter #f) (init-slot slot-index-getter #:getter #f)
(init-slot slot-index-setter #:setter #f) (init-slot slot-index-setter #:setter #f)
(init-slot slot-index-accessor #:accessor #f) (init-slot slot-index-accessor #:accessor #f)
(init-slot slot-index-slot-ref #:slot-ref #f) (struct-set! slot slot-index-slot-ref/raw #f)
(init-slot slot-index-slot-set! #:slot-set! #f) (struct-set! slot slot-index-slot-ref #f)
(init-slot slot-index-index #:index #f) (struct-set! slot slot-index-slot-set! #f)
(init-slot slot-index-size #:size #f) (struct-set! slot slot-index-index #f)
(struct-set! slot slot-index-size #f)
slot)) slot))
;; Boot definition. ;; Boot definition.
@ -678,6 +683,35 @@ followed by its associated value. If @var{l} does not hold a value for
(struct-set! class class-index-nfields (1+ index)) (struct-set! class class-index-nfields (1+ index))
index)) index))
;;; Pre-generate getters and setters for the first 20 slots.
(define-syntax define-standard-accessor-method
(lambda (stx)
(define num-standard-pre-cache 20)
(syntax-case stx ()
((_ ((proc n) arg ...) body)
#`(define proc
(let ((cache (vector #,@(map (lambda (n*)
#`(lambda (arg ...)
(let ((n #,n*))
body)))
(iota num-standard-pre-cache)))))
(lambda (n)
(if (< n #,num-standard-pre-cache)
(vector-ref cache n)
(lambda (arg ...) body)))))))))
(define-standard-accessor-method ((bound-check-get n) o)
(let ((x (struct-ref o n)))
(if (unbound? x)
(slot-unbound o)
x)))
(define-standard-accessor-method ((standard-get n) o)
(struct-ref o n))
(define-standard-accessor-method ((standard-set n) o v)
(struct-set! o n v))
(define (allocate-slots class slots) (define (allocate-slots class slots)
"Transform the computed list of direct slot definitions @var{slots} "Transform the computed list of direct slot definitions @var{slots}
into a corresponding list of effective slot definitions, allocating into a corresponding list of effective slot definitions, allocating
@ -687,6 +721,7 @@ slots as we go."
;; allocates a field to the object. Pretty strange, but we preserve ;; allocates a field to the object. Pretty strange, but we preserve
;; the behavior for backward compatibility. ;; the behavior for backward compatibility.
(let* ((slot (compute-effective-slot-definition class slot)) (let* ((slot (compute-effective-slot-definition class slot))
(name (%slot-definition-name slot))
(index (struct-ref class class-index-nfields)) (index (struct-ref class class-index-nfields))
(g-n-s (compute-get-n-set class slot)) (g-n-s (compute-get-n-set class slot))
(size (- (struct-ref class class-index-nfields) index))) (size (- (struct-ref class class-index-nfields) index)))
@ -696,14 +731,25 @@ slots as we go."
((? integer?) ((? integer?)
(unless (= size 1) (unless (= size 1)
(error "unexpected return from compute-get-n-set")) (error "unexpected return from compute-get-n-set"))
(values #f #f)) (values (standard-get g-n-s)
(if (slot-definition-init-thunk slot)
(standard-get g-n-s)
(bound-check-get g-n-s))
(standard-set g-n-s)))
(((? procedure? get) (? procedure? set)) (((? procedure? get) (? procedure? set))
(values get set)))) (values get
(lambda (get set) (lambda (o)
(struct-set! slot slot-index-index index) (let ((value (get o)))
(struct-set! slot slot-index-size size) (if (unbound? value)
(slot-unbound class o name)
value)))
set))))
(lambda (get/raw get set)
(struct-set! slot slot-index-slot-ref/raw get/raw)
(struct-set! slot slot-index-slot-ref get) (struct-set! slot slot-index-slot-ref get)
(struct-set! slot slot-index-slot-set! set))) (struct-set! slot slot-index-slot-set! set)
(struct-set! slot slot-index-index index)
(struct-set! slot slot-index-size size)))
slot)) slot))
(struct-set! class class-index-nfields 0) (struct-set! class class-index-nfields 0)
(map-in-order make-effective-slot-definition slots)) (map-in-order make-effective-slot-definition slots))
@ -1081,17 +1127,8 @@ function."
(define (slot-ref obj slot-name) (define (slot-ref obj slot-name)
"Return the value from @var{obj}'s slot with the nam var{slot_name}." "Return the value from @var{obj}'s slot with the nam var{slot_name}."
(let ((class (class-of obj))) (let ((class (class-of obj)))
(define (slot-value slot)
(cond
((%slot-definition-slot-ref slot)
=> (lambda (slot-ref) (slot-ref obj)))
(else
(struct-ref obj (%slot-definition-index slot)))))
(define (have-slot slot) (define (have-slot slot)
(let ((val (slot-value slot))) ((%slot-definition-slot-ref slot) obj))
(if (unbound? val)
(slot-unbound class obj slot-name)
val)))
(define (no-slot) (define (no-slot)
(unless (symbol? slot-name) (unless (symbol? slot-name)
(scm-error 'wrong-type-arg #f "Not a symbol: ~S" (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
@ -1106,11 +1143,7 @@ function."
"Set the slot named @var{slot_name} of @var{obj} to @var{value}." "Set the slot named @var{slot_name} of @var{obj} to @var{value}."
(let ((class (class-of obj))) (let ((class (class-of obj)))
(define (have-slot slot) (define (have-slot slot)
(cond ((%slot-definition-slot-set! slot) obj value))
((%slot-definition-slot-set! slot)
=> (lambda (slot-set!) (slot-set! obj value)))
(else
(struct-set! obj (%slot-definition-index slot) value))))
(define (no-slot) (define (no-slot)
(unless (symbol? slot-name) (unless (symbol? slot-name)
(scm-error 'wrong-type-arg #f "Not a symbol: ~S" (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
@ -1122,22 +1155,13 @@ function."
(define (slot-bound? obj slot-name) (define (slot-bound? obj slot-name)
"Return the value from @var{obj}'s slot with the nam var{slot_name}." "Return the value from @var{obj}'s slot with the nam var{slot_name}."
(let ((class (class-of obj))) (let ((class (class-of obj)))
(define (slot-value slot)
(cond
((%slot-definition-slot-ref slot)
=> (lambda (slot-ref) (slot-ref obj)))
(else
(struct-ref obj (%slot-definition-index slot)))))
(define (have-slot slot) (define (have-slot slot)
(not (unbound? (slot-value slot)))) (not (unbound? ((%slot-definition-slot-ref/raw slot) obj))))
(define (no-slot) (define (no-slot)
(unless (symbol? slot-name) (unless (symbol? slot-name)
(scm-error 'wrong-type-arg #f "Not a symbol: ~S" (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
(list slot-name) #f)) (list slot-name) #f))
(let ((val (slot-missing class obj slot-name))) (not (unbound? (slot-missing class obj slot-name))))
(if (unbound? val)
(slot-unbound class obj slot-name)
val)))
(%class-slot-definition class slot-name have-slot no-slot))) (%class-slot-definition class slot-name have-slot no-slot)))
(define (slot-exists? obj slot-name) (define (slot-exists? obj slot-name)
@ -2408,7 +2432,7 @@ function."
(let ((slot (class-slot-definition class slot-name))) (let ((slot (class-slot-definition class slot-name)))
(unless (memq (%slot-definition-allocation slot) '(#:class #:each-subclass)) (unless (memq (%slot-definition-allocation slot) '(#:class #:each-subclass))
(slot-missing class slot-name)) (slot-missing class slot-name))
(let ((x ((%slot-definition-slot-ref slot) #f))) (let ((x ((%slot-definition-slot-ref/raw slot) #f)))
(if (unbound? x) (if (unbound? x)
(slot-unbound class slot-name) (slot-unbound class slot-name)
x)))) x))))
@ -2611,25 +2635,17 @@ function."
slots)) slots))
(define-method (compute-getter-method (class <class>) slot) (define-method (compute-getter-method (class <class>) slot)
(let ((init-thunk (slot-definition-init-thunk slot)) (let ((slot-ref (slot-definition-slot-ref slot)))
(slot-ref (slot-definition-slot-ref slot))
(index (slot-definition-index slot)))
(make <accessor-method> (make <accessor-method>
#:specializers (list class) #:specializers (list class)
#:procedure (cond #:procedure slot-ref
(slot-ref (make-generic-bound-check-getter slot-ref))
(init-thunk (standard-get index))
(else (bound-check-get index)))
#:slot-definition slot))) #:slot-definition slot)))
(define-method (compute-setter-method (class <class>) slot) (define-method (compute-setter-method (class <class>) slot)
(let ((slot-set! (slot-definition-slot-set! slot)) (let ((slot-set! (slot-definition-slot-set! slot)))
(index (slot-definition-index slot)))
(make <accessor-method> (make <accessor-method>
#:specializers (list class <top>) #:specializers (list class <top>)
#:procedure (cond #:procedure slot-set!
(slot-set! slot-set!)
(else (standard-set index)))
#:slot-definition slot))) #:slot-definition slot)))
(define (make-generic-bound-check-getter proc) (define (make-generic-bound-check-getter proc)
@ -2639,35 +2655,6 @@ function."
(slot-unbound o) (slot-unbound o)
val)))) val))))
;;; Pre-generate getters and setters for the first 20 slots.
(define-syntax define-standard-accessor-method
(lambda (stx)
(define num-standard-pre-cache 20)
(syntax-case stx ()
((_ ((proc n) arg ...) body)
#`(define proc
(let ((cache (vector #,@(map (lambda (n*)
#`(lambda (arg ...)
(let ((n #,n*))
body)))
(iota num-standard-pre-cache)))))
(lambda (n)
(if (< n #,num-standard-pre-cache)
(vector-ref cache n)
(lambda (arg ...) body)))))))))
(define-standard-accessor-method ((bound-check-get n) o)
(let ((x (struct-ref o n)))
(if (unbound? x)
(slot-unbound o)
x)))
(define-standard-accessor-method ((standard-get n) o)
(struct-ref o n))
(define-standard-accessor-method ((standard-set n) o v)
(struct-set! o n v))
;;; compute-cpl ;;; compute-cpl
;;; ;;;
@ -2778,11 +2765,7 @@ var{initargs}."
(() obj) (() obj)
((slot . slots) ((slot . slots)
(define (initialize-slot! value) (define (initialize-slot! value)
(cond ((%slot-definition-slot-set! slot) obj value))
((%slot-definition-slot-set! slot)
=> (lambda (slot-set!) (slot-set! obj value)))
(else
(struct-set! obj (%slot-definition-index slot) value))))
(let ((initarg (get-initarg (%slot-definition-init-keyword slot)))) (let ((initarg (get-initarg (%slot-definition-init-keyword slot))))
(cond (cond
((not (unbound? initarg)) ((not (unbound? initarg))