summaryrefslogtreecommitdiff
path: root/class.c
AgeCommit message (Collapse)Author
2025-12-04Take VM lock in `class_switch_superclass` (#15356)Luke Gruber
Safe multi-ractor subclass list mutation We need to lock around mutation and accesses of a class's subclasses list. Unfortunately we also need to do this when creating singleton classes, as the singleton class does need to go into `super`'s subclasses list for CC invalidation purposes.
2025-12-02Box: Free rb_classext_t struct for a box when the box is GCedSatoshi Tagomori
2025-11-20Fix missing write barrier on namespace classextJohn Hawthorn
Found by wbcheck It seems like here the classext was associated with the class, but it already had Ruby objects attached. rb_gc_writebarrier_remember works around that issue, but I suspect if we enabled autocompaction the values copied into the classext before it was attached could be broken.
2025-11-10Fix printf specificer. %lp doesn't make sense. Triggered -WformatAlan Wu
2025-11-11Revert "ns_subclasses refcount accesses need to be atomic (#15083)" (#15138)Luke Gruber
This reverts commit 2998c8d6b99ec49925ebea42198b29c3e27b34a7. We need to find a better way to fix this bug. Even with this refcount change, errors were still being seen in CI. For now we need to remove this failing test.
2025-11-10Remove unused subclass methodsJohn Hawthorn
2025-11-10Fix memory leak in subclasses when freeing classextPeter Zhu
We don't decrement the super and module subclasses count for iclasses that are having their classext replaced. This causes the reference count to be incorrect and leak memory. The following script demonstrates the memory leak: module Foo refine(Object) do define_method(:<=) {} end end class Bar include Comparable end With RUBY_FREE_AT_EXIT and ASAN, we can see many memory leaks, including: Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x599f715adca2 in calloc (miniruby+0x64ca2) #1 0x599f716bd779 in calloc1 gc/default/default.c:1495:12 #2 0x599f716d1370 in rb_gc_impl_calloc gc/default/default.c:8216:5 #3 0x599f716b8ab1 in ruby_xcalloc_body gc.c:5221:12 #4 0x599f716b269c in ruby_xcalloc gc.c:5215:34 #5 0x599f715eab23 in class_alloc0 class.c:790:22 #6 0x599f715e4bec in class_alloc class.c:836:12 #7 0x599f715e60c9 in module_new class.c:1693:17 #8 0x599f715e60a2 in rb_module_new class.c:1701:12 #9 0x599f715e6303 in rb_define_module class.c:1733:14 #10 0x599f715ebc5f in Init_Comparable compar.c:315:22 #11 0x599f716e35f5 in rb_call_inits inits.c:32:5 #12 0x599f7169cbfd in ruby_setup eval.c:88:9 #13 0x599f7169cdac in ruby_init eval.c:100:17 #14 0x599f715b0fa9 in rb_main main.c:41:5 #15 0x599f715b0f59 in main main.c:62:12 #16 0x739b2f02a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #17 0x739b2f02a28a in __libc_start_main csu/../csu/libc-start.c:360:3 #18 0x599f7157c424 in _start (miniruby+0x33424)
2025-11-07Use RUBY_BOX environment variable instead of RUBY_NAMESPACESatoshi Tagomori
2025-11-07renaming internal data structures and functions from namespace to boxSatoshi Tagomori
2025-11-07update referenced filenames from namespace to boxSatoshi Tagomori
2025-11-06ns_subclasses refcount accesses need to be atomic (#15083)Luke Gruber
We were seeing errors like: ``` * thread #8, stop reason = EXC_BAD_ACCESS (code=1, address=0x803) * frame #0: 0x00000001001fe944 ruby`rb_st_lookup(tab=0x00000000000007fb, key=1, value=0x00000001305b7490) at st.c:1066:22 frame #1: 0x000000010002d658 ruby`remove_class_from_subclasses [inlined] class_get_subclasses_for_ns(tbl=0x00000000000007fb, ns_id=1) at class.c:604:9 frame #2: 0x000000010002d650 ruby`remove_class_from_subclasses(tbl=0x00000000000007fb, ns_id=1, klass=4754039232) at class.c:620:34 frame #3: 0x000000010002c8a8 ruby`rb_class_classext_free_subclasses(ext=0x000000011b5ce1d8, klass=4754039232, replacing=<unavailable>) at class.c:700:9 frame #4: 0x000000010002c760 ruby`rb_class_classext_free(klass=4754039232, ext=0x000000011b5ce1d8, is_prime=true) at class.c:105:5 frame #5: 0x00000001000e770c ruby`classext_free(ext=<unavailable>, is_prime=<unavailable>, namespace=<unavailable>, arg=<unavailable>) at gc.c:1231:5 [artificial] frame #6: 0x000000010002d178 ruby`rb_class_classext_foreach(klass=<unavailable>, func=(ruby`classext_free at gc.c:1228), arg=0x00000001305b75c0) at class.c:518:5 frame #7: 0x00000001000e745c ruby`rb_gc_obj_free(objspace=0x000000012500c400, obj=4754039232) at gc.c:1282:9 frame #8: 0x00000001000e70d4 ruby`gc_sweep_plane(objspace=0x000000012500c400, heap=<unavailable>, p=4754039232, bitset=4095, ctx=0x00000001305b76e8) at default.c:3482:21 frame #9: 0x00000001000e6e9c ruby`gc_sweep_page(objspace=0x000000012500c400, heap=0x000000012500c540, ctx=0x00000001305b76e8) at default.c:3567:13 frame #10: 0x00000001000e51d0 ruby`gc_sweep_step(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:3848:9 frame #11: 0x00000001000e1880 ruby`gc_continue [inlined] gc_sweep_continue(objspace=0x000000012500c400, sweep_heap=0x000000012500c540) at default.c:3931:13 frame #12: 0x00000001000e1754 ruby`gc_continue(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2037:9 frame #13: 0x00000001000e10bc ruby`newobj_cache_miss [inlined] heap_prepare(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2056:5 frame #14: 0x00000001000e1074 ruby`newobj_cache_miss [inlined] heap_next_free_page(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2280:9 frame #15: 0x00000001000e106c ruby`newobj_cache_miss(objspace=0x000000012500c400, cache=0x0000600001b00300, heap_idx=2, vm_locked=false) at default.c:2387:38 frame #16: 0x00000001000e0d28 ruby`newobj_alloc(objspace=<unavailable>, cache=<unavailable>, heap_idx=<unavailable>, vm_locked=<unavailable>) at default.c:2411:15 [artificial] frame #17: 0x00000001000d7214 ruby`newobj_of [inlined] rb_gc_impl_new_obj(objspace_ptr=<unavailable>, cache_ptr=<unavailable>, klass=<unavailable>, flags=<unavailable>, wb_protected=<unavailable>, alloc_size=<unavailable>) at default.c:2490:15 frame #18: 0x00000001000d719c ruby`newobj_of(cr=<unavailable>, klass=4313971728, flags=258, wb_protected=<unavailable>, size=<unavailable>) at gc.c:995:17 frame #19: 0x00000001000d73ec ruby`rb_wb_protected_newobj_of(ec=<unavailable>, klass=<unavailable>, flags=<unavailable>, size=<unavailable>) at gc.c:1044:12 [artificial] frame #20: 0x0000000100032d34 ruby`class_alloc0(type=<unavailable>, klass=4313971728, namespaceable=<unavailable>) at class.c:803:5 ```
2025-11-03No need to call rb_define_class/module_under_idSatoshi Tagomori
Classes/modules defined in a namespace are defined under ::Object as usual (as without namespaces), and it'll be set into the const_tbl of ::Object. In namespaces, namespace objects' const_tbl is equal to the one of ::Object. So constants of ::Object are just equal to constants of the namespace. That means, top level classes/modules in a namespace can be referred as namespace::KlassName without calling rb_define_class_under_id().
2025-10-26Stop deleting the reference from superclass when replacing classext.Satoshi Tagomori
Calling the usual rb_iclass_classext_free() causes SEGV because duplicating a newer classext of iclass had set the reference from superclass to the newer classext, but calling rb_iclass_classext_free() deletes it.
2025-10-26free the entry after deleting the referenceSatoshi Tagomori
2025-10-26classext replacement never happen on non-iclass classesSatoshi Tagomori
2025-10-23use `SET_SHAREABLE`Koichi Sasada
to adopt strict shareable rule. * (basically) shareable objects only refer shareable objects * (exception) shareable objects can refere unshareable objects but should not leak reference to unshareable objects to Ruby world
2025-10-21Fix memory leak in RCLASS_SET_NAMESPACE_CLASSEXTPeter Zhu
The st_insert in RCLASS_SET_NAMESPACE_CLASSEXT may overwrite an existing rb_classext_t, causing it to leak memory. This commit changes it to use st_update to free the existing one before overwriting it.
2025-10-21Move rb_class_classext_free to class.cPeter Zhu
2025-10-17Preallocate capacity for id table in rb_singleton_class_clone_and_attachPeter Zhu
We know the exact capacity for the constant table created in rb_singleton_class_clone_and_attach so we can preallocate it.
2025-10-17Set method table owned by iclass in rb_class_duplicate_classextPeter Zhu
We duplicate the method table in rb_class_duplicate_classext, so we should set RCLASSEXT_ICLASS_IS_ORIGIN and unset RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL to signal that the iclass owns the method table and it should be freed.
2025-10-16Fix crash when freeing namespacesPeter Zhu
remove_class_from_subclasses calls st_insert, which mallocs. Malloc is not allowed in GC. This commit replaces the st_insert with an st_update since we know that ns_id exists in the st_table. The following script reproduces the crash: require "tempfile" Tempfile.create do |file| ns = Namespace.new ns.require(file) end
2025-10-14Remove a comment - we cannot remove this method now probablySatoshi Tagomori
2025-10-02ZJIT: Add `NoSingletonClass` patch point (#14680)Stan Lo
* ZJIT: Add NoSingletonClass patch point This patch point makes sure that when the object has a singleton class, the JIT code is invalidated. As of now, this is only needed for C call optimization. In YJIT, the singleton class guard only applies to Array, Hash, and String. But in ZJIT, we may optimize C calls from gems (e.g. `sqlite3`). So the patch point needs to be applied to a broader range of classes. * ZJIT: Only generate NoSingletonClass guard when the type can have singleton class * ZJIT: Update or forget NoSingletonClass patch point when needed
2025-09-29zeroing on the table to suppress unintentional call of classext_foreachSatoshi Tagomori
2025-09-29Update current namespace management by using control frames and lexical contextsSatoshi Tagomori
to fix inconsistent and wrong current namespace detections. This includes: * Moving load_path and related things from rb_vm_t to rb_namespace_t to simplify accessing those values via namespace (instead of accessing either vm or ns) * Initializing root_namespace earlier and consolidate builtin_namespace into root_namespace * Adding VM_FRAME_FLAG_NS_REQUIRE for checkpoints to detect a namespace to load/require files * Removing implicit refinements in the root namespace which was used to determine the namespace to be loaded (replaced by VM_FRAME_FLAG_NS_REQUIRE) * Removing namespaces from rb_proc_t because its namespace can be identified by lexical context * Starting to use ep[VM_ENV_DATA_INDEX_SPECVAL] to store the current namespace when the frame type is MAGIC_TOP or MAGIC_CLASS (block handlers don't exist in this case)
2025-09-17Clear object_id for newly allocated classPeter Zhu
2025-08-30object.c: improve fake_class_p to also handle T_MODULEJean Boussier
This requires ensuring T_MODULE never has FL_SINGLETON set, so RMODULE_IS_REFINEMENT had to be moved.
2025-07-23Cleanup M_TBL workarounds and commentsJohn Hawthorn
Previously we had an assertion that the method table was only set on young objects, and a comment stating that was how it needed to be used. I think that confused the complexity of the write barriers that may be needed here. * Setting an empty M_TBL never needs a write barrier * T_CLASS and T_MODULE should always fire a write barrier to newly added methods * T_ICLASS only needs a write barrier to methods when RCLASSEXT_ICLASS_IS_ORIGIN(x) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(x) We shouldn't assume that the object being young is sufficient, because we also need write barriers for incremental marking and it's unreliable.
2025-07-23Fix missing write barrier through M_TBLJohn Hawthorn
When creating a new origin in ensure_origin, we need to fire a write barrier after RCLASS_WRITE_ORIGIN. rb_class_set_super allocates, so GC could happen there, either incrementally marking or promoting the newly allocated class, and only after RCLASS_WRITE_ORIGIN will origin mark object in the M_TBL.
2025-07-01class.c: Stop deleting __classpath__ / __tmp_classpath__Jean Boussier
These used to be private variables to store the class name but aren't a thing since several versions.
2025-06-24Refactor rewrite_crefJohn Hawthorn
2025-06-24Reduce exposure of FL_FREEZEJean Boussier
The `FL_FREEZE` flag is redundant with `SHAPE_ID_FL_FROZEN`, so ideally it should be eliminated in favor of the later. Doing so would eliminate the risk of desync between the two, but also solve the problem of the frozen status being global in namespace context (See Bug #21330).
2025-06-23Allocate singleton classes as namespaceable if their parent areJean Boussier
2025-06-23Shink RClass when it is known they can't be namespacedJean Boussier
Even when namespaces are enabled, only a few core classes created during init will eventually be namespaced. For these it's OK to allocate a 320B slot to hold the extra namespace stuff. But for any class created post init, we know we'll never need the namespace and we can fit in a 160B slot.
2025-06-23Mark RClass instance that may be namespaced with RCLASS_NAMESPACEABLEJean Boussier
2025-06-17Rename `imemo_class_fields` -> `imemo_fields`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13626
2025-06-12Turn `rb_classext_t.fields` into a T_IMEMO/class_fieldsJean Boussier
This behave almost exactly as a T_OBJECT, the layout is entirely compatible. This aims to solve two problems. First, it solves the problem of namspaced classes having a single `shape_id`. Now each namespaced classext has an object that can hold the namespace specific shape. Second, it open the door to later make class instance variable writes atomics, hence be able to read class variables without locking the VM. In the future, in multi-ractor mode, we can do the write on a copy of the `fields_obj` and then atomically swap it. Considerations: - Right now the `RClass` shape_id is always synchronized, but with namespace we should likely mark classes that have multiple namespace with a specific shape flag. Notes: Merged: https://github.com/ruby/ruby/pull/13411
2025-05-29Read {max_iv,variation}_count from prime classextJohn Hawthorn
MAX_IV_COUNT is a hint which determines the size of variable width allocation we should use for a given class. We don't need to scope this by namespace, if we end up with larger builtin objects on some namespaces that isn't a user-visible problem, just extra memory use. Similarly variation_count is used to track if a given object has had too many branches in shapes it has used, and to use too_complex when that happens. That's also just a hint, so we can use the same value across namespaces without it being visible to users. Previously variation_count was being incremented (written to) on the RCLASS_EXT_READABLE ext, which seems incorrect if we wanted it to be different across namespaces Notes: Merged: https://github.com/ruby/ruby/pull/13434
2025-05-28Use flag for RCLASS_IS_INITIALIZEDJohn Hawthorn
Previously we used a flag to set whether a module was uninitialized. When checked whether a class was initialized, we first had to check that it had a non-zero superclass, as well as that it wasn't BasicObject. With the advent of namespaces, RCLASS_SUPER is now an expensive operation, and though we could just check for the prime superclass, we might as well take this opportunity to use a flag so that we can perform the initialized check with as few instructions as possible. It's possible in the future that we could prevent uninitialized classes from being available to the user, but currently there are a few ways to do that. Notes: Merged: https://github.com/ruby/ruby/pull/13443
2025-05-28Make class_alloc only accept typeJohn Hawthorn
If any other flags were passed other than type they were ignored, so we might as well be more explicit that that's all this accepts. This also fixes the incorrect (internal) documentation. It also turns out type is always known in the caller, so I made it explicit in the two places additional flags were being passed. Notes: Merged: https://github.com/ruby/ruby/pull/13446
2025-05-26Add shape_id to RBasic under 32 bitJohn Hawthorn
This makes `RBobject` `4B` larger on 32 bit systems but simplifies the implementation a lot. [Feature #21353] Co-authored-by: Jean Boussier <byroot@ruby-lang.org> Notes: Merged: https://github.com/ruby/ruby/pull/13341
2025-05-25Use RB_VM_LOCKINGNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/13439
2025-05-23Only call RCLASS_SET_ALLOCATOR on T_CLASS objectsJohn Hawthorn
It's invalid to set an allocator on a T_ICLASS or T_MODULE, as those use the other fields from the union. Notes: Merged: https://github.com/ruby/ruby/pull/13416
2025-05-23Don't use namespaced classext for superclassesJohn Hawthorn
Superclasses can't be modified by user code, so do not need namespace indirection. For example Object.superclass is always BasicObject, no matter what modules are included onto it. Notes: Merged: https://github.com/ruby/ruby/pull/13420
2025-05-22Remove assertion on field in `class_duplicate_iclass_classext`Aaron Patterson
`ext` is newly allocated so it shouldn't need an assertion. The class ext (which is always from the module) that we're passing to `class_duplicate_iclass_classext` could legitimately have instance variables on it. We just want to avoid copying them. The assertion was making this crash: ``` $ RUBY_NAMESPACE=1 ./miniruby -e1 ``` Notes: Merged: https://github.com/ruby/ruby/pull/13419
2025-05-22Namespaces: Don't initialize fields for T_ICLASSJean Boussier
ICLASS don't have instance variables or anything like that. `gc_mark_classext_iclass` didn't mark it, and `classext_iclass_free` wasn't freeing it. Notes: Merged: https://github.com/ruby/ruby/pull/13409
2025-05-21Update class.cAaron Patterson
Co-authored-by: Satoshi Tagomori <tagomoris@gmail.com> Notes: Merged: https://github.com/ruby/ruby/pull/13385
2025-05-21Add assertion for RCLASS_SET_PRIME_CLASSEXT_WRITABLEAaron Patterson
When classes are booted, they should all be writeable unless namespaces are enabled. This commit adds an assertion to ensure that classes are writable. Notes: Merged: https://github.com/ruby/ruby/pull/13385
2025-05-14Reclaim one `VALUE` from `rb_classext_t` by shrinking `super_classdepth`Jean Boussier
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: Merged: https://github.com/ruby/ruby/pull/13319
2025-05-11Delete code for debugging namespaceSatoshi Tagomori