1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-18 01:30:27 +02:00

Implement class redefinition on top of fixed structs

* libguile/struct.h: Steal another flag for GOOPS.
* libguile/goops.h (SCM_VTABLE_FLAG_GOOPS_INDIRECT)
  (SCM_VTABLE_FLAG_GOOPS_NEEDS_MIGRATION): New flags.
  (SCM_CLASSF_GOOPS_VALID, SCM_CLASSF_GOOPS_OR_VALID): Remove obsolete
  definitions.
  (SCM_IS_A_P): Use the scm_class_of function.
* libguile/goops.c (var_class_of_obsolete_indirect_instance): Rename
  from var_migrate_instance.
  (scm_is_generic, scm_is_method, scm_sys_init_layout_x): Use
  scm_class_of instead of the SCM_CLASS_OF macro.
  (get_indirect_slots): New helper.
  (scm_class_of): This patch moves us in a direction where we won't be
  able to separately address a struct's data and its identity.
  Therefore to check whether a class needs migration, we check an
  embedded pointer from a slot instead of the vtable data.
  (scm_sys_struct_data): Remove this temporary function.
  (scm_sys_modify_instance): Update to swap slot values instead of the
  data pointers themselves.
  (scm_sys_modify_class): Use scm_sys_modify_instance.
  (scm_sys_goops_loaded): Capture class-of-obsolete-indirect-instance
  instead of migrate-instance.
  (scm_init_goops_builtins): Don't export the "valid" flag any more;
  export instead the "indirect" and "needs-migration" flags.
* libguile/foreign-object.c (scm_assert_foreign_object_type): Add a
  FIXME.
* libguile/vm-engine.c (class-of): Take away fast path for the time
  being.
* module/oop/goops.scm (class-has-indirect-instances?)
  (indirect-slots-need-migration?): New helpers.
  (<class>, <slot>, %class-slot-definition, initialize): Remove use of
  vtable-flag-goops-valid.
  (define-class): Always push redefined values through
  `class-redefinition'.
  (<redefinable-class>): New public definition.  Use it as a metaclass
  for redefinable classes.  Provide a compute-slots function that
  declares the indirect slots mechanism.  Add the "indirect" flag to
  instances of <redefinable-class>.  Create indirect-slots objects for
  instances of those classes as part of their allocate-instance.
  (change-object-class, class-of-obsolete-indirect-instance): Update for
  new representation change.
* test-suite/tests/goops.test ("object update"): Add #:metaclass
  <redefinable-class> to all redefinable classes.  For the "hell" test,
  make the new classes with class-direct-slots, not class-slots; this
  was an error in the test.
This commit is contained in:
Andy Wingo 2017-09-08 10:44:54 +02:00
parent 5c8bb13630
commit 4898959901
7 changed files with 472 additions and 287 deletions

View file

@ -337,25 +337,31 @@
(with-test-prefix "object update"
(pass-if "defining class"
(eval '(define-class <foo> ()
(x #:accessor x #:init-value 123)
(z #:accessor z #:init-value 789))
(current-module))
(x #:accessor x #:init-value 123)
(z #:accessor z #:init-value 789)
#:metaclass <redefinable-class>)
(current-module))
(eval '(is-a? <foo> <class>) (current-module)))
(pass-if "making instance"
(eval '(define foo (make <foo>)) (current-module))
(eval '(and (is-a? foo <foo>) (= (x foo) 123)) (current-module)))
(pass-if "redefining class"
(eval '(define-class <foo> ()
(x #:accessor x #:init-value 123)
(y #:accessor y #:init-value 456)
(z #:accessor z #:init-value 789))
(current-module))
(x #:accessor x #:init-value 123)
(y #:accessor y #:init-value 456)
(z #:accessor z #:init-value 789)
#:metaclass <redefinable-class>)
(current-module))
(eval '(and (= (y foo) 456) (= (z foo) 789)) (current-module)))
(pass-if "changing class"
(let* ((c1 (class () (the-slot #:init-keyword #:value)))
(c2 (class () (the-slot #:init-keyword #:value)
(the-other-slot #:init-value 888)))
(let* ((c1 (class ()
(the-slot #:init-keyword #:value)
#:metaclass <redefinable-class>))
(c2 (class ()
(the-slot #:init-keyword #:value)
(the-other-slot #:init-value 888)
#:metaclass <redefinable-class>))
(o1 (make c1 #:value 777)))
(and (is-a? o1 c1)
(not (is-a? o1 c2))
@ -373,7 +379,8 @@
;; array, leading to out-of-bounds accesses.
(let* ((parent-class (class ()
#:name '<class-that-will-be-redefined>))
#:name '<class-that-will-be-redefined>
#:metaclass <redefinable-class>))
(classes
(unfold (lambda (i) (>= i 20))
(lambda (i)
@ -383,7 +390,8 @@
#:name (string->symbol
(string-append "<foo-to-redefine-"
(number->string i)
">"))))
">"))
#:metaclass <redefinable-class>))
(lambda (i)
(+ 1 i))
0))
@ -393,7 +401,7 @@
classes)))
(define-method (change-class (foo parent-class)
(new <class>))
(new <redefinable-class>))
;; Called by `scm_change_object_class ()', via `purgatory ()'.
(if (null? classes)
(next-method)
@ -407,8 +415,9 @@
;; nested `scm_change_object_class ()' calls, which increases
;; the size of HELL and increments N_HELL.
(class-redefinition class
(make-class '() (class-slots class)
#:name (class-name class)))
(make-class '() (class-direct-slots class)
#:name (class-name class)
#:metaclass <redefinable-class>))
;; Use `slot-ref' to trigger the `scm_change_object_class ()'
;; and `go_to_hell ()' calls.