diff options
author | Jean Boussier <[email protected]> | 2025-05-13 16:27:43 +0200 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2025-05-14 10:17:03 +0200 |
commit | 130d6aaef297ec43ed24f413624088f41bc616b3 (patch) | |
tree | 452251c0e321e5ca86205cd674bd5765e49d611b | |
parent | f855bcc6b27bd2e67babbb082213ab4c9c15f8c9 (diff) |
Reclaim one `VALUE` from `rb_classext_t` by shrinking `super_classdepth`
By making `super_classdepth` `uint16_t`, classes and modules can
now fit in 160B slots again.
The downside of course is that before `super_classdepth` was large
enough we never had to care about overflow, as you couldn't
realistically create enough classes to ever go over it.
With this change, while it is stupid, you could realistically
create an ancestor chain containing 65k classes and modules.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/13319
-rw-r--r-- | class.c | 4 | ||||
-rw-r--r-- | internal/class.h | 11 |
2 files changed, 11 insertions, 4 deletions
@@ -827,7 +827,9 @@ rb_class_update_superclasses(VALUE klass) superclasses = class_superclasses_including_self(super); RCLASS_WRITE_SUPERCLASSES(super, super_depth, superclasses, true, true); } - RCLASS_WRITE_SUPERCLASSES(klass, super_depth + 1, superclasses, false, false); + + size_t depth = super_depth == RCLASS_MAX_SUPERCLASS_DEPTH ? super_depth : super_depth + 1; + RCLASS_WRITE_SUPERCLASSES(klass, depth, superclasses, false, false); } void diff --git a/internal/class.h b/internal/class.h index 25b02ca3e0..e83dd31bea 100644 --- a/internal/class.h +++ b/internal/class.h @@ -85,7 +85,6 @@ struct rb_classext_struct { struct rb_id_table *callable_m_tbl; struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */ struct rb_id_table *cvc_tbl; - size_t superclass_depth; VALUE *superclasses; /** * The head of subclasses is a blank (w/o klass) entry to be referred from anchor (and be never deleted). @@ -121,6 +120,7 @@ struct rb_classext_struct { } iclass; } as; attr_index_t max_iv_count; + uint16_t superclass_depth; unsigned char variation_count; bool permanent_classpath : 1; bool cloned : 1; @@ -145,14 +145,17 @@ struct RClass { }; // Assert that classes can be embedded in heaps[2] (which has 160B slot size) -// TODO: restore this assertion after removing several fields from rb_classext_t -// STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t) <= 4 * RVALUE_SIZE); +// On 32bit platforms there is no variable width allocation so it doesn't matter. +// TODO: restore this assertion after shrinking rb_classext_t +// STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t) <= 4 * RVALUE_SIZE || SIZEOF_VALUE < SIZEOF_LONG_LONG); struct RClass_and_rb_classext_t { struct RClass rclass; rb_classext_t classext; }; +static const uint16_t RCLASS_MAX_SUPERCLASS_DEPTH = ((uint16_t)-1); + static inline bool RCLASS_SINGLETON_P(VALUE klass); static inline bool RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE obj); @@ -712,6 +715,8 @@ RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass) static inline void RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool owns_it, bool with_self) { + RUBY_ASSERT(depth <= RCLASS_MAX_SUPERCLASS_DEPTH); + rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); RCLASSEXT_SUPERCLASS_DEPTH(ext) = depth; RCLASSEXT_SUPERCLASSES(ext) = superclasses; |