summaryrefslogtreecommitdiff
path: root/internal/class.h
Commit message (Collapse)AuthorAgeFilesLines
* Make classes embedded on 32 bitPeter Zhu2023-04-161-10/+1
| | | | | Classes are now exactly 80 bytes when embedded, which perfectly fits the 3rd size pool on 32 bit systems.
* Move shape ID to flags for classes on 32 bitPeter Zhu2023-04-161-3/+0
| | | | | | Moves shape ID to FL_USER4 to FL_USER19 for the shape ID on 32 bit systems. This makes the rb_classext_struct smaller so that it can be embedded.
* Move RCLASS_CLONED to rb_classext_structPeter Zhu2023-04-161-2/+2
| | | | | This commit moves RCLASS_CLONED from the flags to the rb_classext_struct. This frees the FL_USER1 bit.
* Change max_iv_count to type attr_index_tPeter Zhu2023-04-111-1/+1
| | | | | | max_iv_count is calculated from next_iv_index of the shape, which is of type attr_index_t, so we can also make max_iv_count of type attr_index_t.
* Revert "Allow classes and modules to become too complex"Aaron Patterson2023-03-101-1/+0
| | | | This reverts commit 69465df4242f3b2d8e55fbe18d7c45b47b40a626.
* Allow classes and modules to become too complexHParker2023-03-091-0/+1
| | | | This makes the behavior of classes and modules when there are too many instance variables match the behavior of objects with too many instance variables.
* Stop exporting symbols for MJITTakashi Kokubun2023-03-061-2/+0
|
* Move `attached_object` into `rb_classext_struct`Jean Boussier2023-02-161-5/+27
| | | | | | Given that signleton classes don't have an allocator, we can re-use these bytes to store the attached object in `rb_classext_struct` without making it larger.
* Encapsulate RCLASS_ATTACHED_OBJECTJean Boussier2023-02-151-0/+13
| | | | | | | | | Right now the attached object is stored as an instance variable and all the call sites that either get or set it have to know how it's stored. It's preferable to hide this implementation detail behind accessors so that it is easier to change how it's stored.
* Check !RCLASS_EXT_EMBEDDED instead of SIZE_POOL_COUNT == 1Jean Boussier2023-02-151-1/+1
| | | | It's much more self documenting and consistent
* Don't redefine RB_OBJ_WRITEPeter Zhu2023-01-181-1/+0
| | | | | RB_OBJ_WRITE already exists in rgengc.h, so we shouldn't redefine it in gc.h.
* Move classpath to rb_classext_tPeter Zhu2023-01-111-2/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit moves the classpath (and tmp_classpath) from instance variables to the rb_classext_t. This improves performance as we no longer need to set an instance variable when assigning a classpath to a class. I benchmarked with the following script: ```ruby name = :MyClass puts(Benchmark.measure do 10_000_000.times do |i| Object.const_set(name, Class.new) Object.send(:remove_const, name) end end) ``` Before this patch: ``` 5.440119 0.025264 5.465383 ( 5.467105) ``` After this patch: ``` 4.889646 0.028325 4.917971 ( 4.942678) ```
* Make variation_count an unsigned charPeter Zhu2023-01-111-2/+7
| | | | | Since SHAPE_MAX_VARIATIONS is 8, it can easily fit inside an unsigned char.
* Add variation_count on classesJemma Issroff2022-12-151-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | Count how many "variations" each class creates. A "variation" is a a unique ordering of instance variables on a particular class. This can also be thought of as a branch in the shape tree. For example, the following Foo class will have 2 variations: ```ruby class Foo ; end Foo.new.instance_variable_set(:@a, 1) # case 1: creates one variation Foo.new.instance_variable_set(:@b, 1) # case 2: creates another variation foo = Foo.new foo.instance_variable_set(:@a, 1) # does not create a new variation foo.instance_variable_set(:@b, 1) # does not create a new variation (a continuation of the variation in case 1) ``` We will use this number to limit the amount of shapes that a class can create and fallback to using a hash iv lookup. Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
* Transition shape when object's capacity changesJemma Issroff2022-11-101-2/+2
| | | | | | | | | | | | | | | | This commit adds a `capacity` field to shapes, and adds shape transitions whenever an object's capacity changes. Objects which are allocated out of a bigger size pool will also make a transition from the root shape to the shape with the correct capacity for their size pool when they are allocated. This commit will allow us to remove numiv from objects completely, and will also mean we can guarantee that if two objects share shapes, their IVs are in the same positions (an embedded and extended object cannot share shapes). This will enable us to implement ivar sets in YJIT using object shapes. Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
* Implement object shapes for T_CLASS and T_MODULE (#6637)John Hawthorn2022-10-311-2/+2
| | | | | | | | * Avoid RCLASS_IV_TBL in marshal.c * Avoid RCLASS_IV_TBL for class names * Avoid RCLASS_IV_TBL for autoload * Avoid RCLASS_IV_TBL for class variables * Avoid copying RCLASS_IV_TBL onto ICLASSes * Use object shapes for Class and Module IVs
* Remove iv_index_tbl_entryJohn Hawthorn2022-10-241-6/+0
|
* Remove unused class serialJemma Issroff2022-10-211-30/+2
| | | | | | | | Before object shapes, we were using class serial to invalidate inline caches. Now that we use shape_id for inline cache keys, the class serial is unnecessary. Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
* Revert "Revert "This commit implements the Object Shapes technique in CRuby.""Jemma Issroff2022-10-111-4/+7
| | | | This reverts commit 9a6803c90b817f70389cae10d60b50ad752da48f.
* Revert "This commit implements the Object Shapes technique in CRuby."Aaron Patterson2022-09-301-7/+4
| | | | This reverts commit 68bc9e2e97d12f80df0d113e284864e225f771c2.
* This commit implements the Object Shapes technique in CRuby.Jemma Issroff2022-09-281-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Object Shapes is used for accessing instance variables and representing the "frozenness" of objects. Object instances have a "shape" and the shape represents some attributes of the object (currently which instance variables are set and the "frozenness"). Shapes form a tree data structure, and when a new instance variable is set on an object, that object "transitions" to a new shape in the shape tree. Each shape has an ID that is used for caching. The shape structure is independent of class, so objects of different types can have the same shape. For example: ```ruby class Foo def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end class Bar def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end foo = Foo.new # `foo` has shape id 2 bar = Bar.new # `bar` has shape id 2 ``` Both `foo` and `bar` instances have the same shape because they both set instance variables of the same name in the same order. This technique can help to improve inline cache hits as well as generate more efficient machine code in JIT compilers. This commit also adds some methods for debugging shapes on objects. See `RubyVM::Shape` for more details. For more context on Object Shapes, see [Feature: #18776] Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org> Co-Authored-By: Eileen M. Uchitelle <eileencodes@gmail.com> Co-Authored-By: John Hawthorn <john@hawthorn.email>
* Revert this until we can figure out WB issues or remove shapes from GCAaron Patterson2022-09-261-6/+5
| | | | | | | | | | Revert "* expand tabs. [ci skip]" This reverts commit 830b5b5c351c5c6efa5ad461ae4ec5085e5f0275. Revert "This commit implements the Object Shapes technique in CRuby." This reverts commit 9ddfd2ca004d1952be79cf1b84c52c79a55978f4.
* This commit implements the Object Shapes technique in CRuby.Jemma Issroff2022-09-261-5/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Object Shapes is used for accessing instance variables and representing the "frozenness" of objects. Object instances have a "shape" and the shape represents some attributes of the object (currently which instance variables are set and the "frozenness"). Shapes form a tree data structure, and when a new instance variable is set on an object, that object "transitions" to a new shape in the shape tree. Each shape has an ID that is used for caching. The shape structure is independent of class, so objects of different types can have the same shape. For example: ```ruby class Foo def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end class Bar def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end foo = Foo.new # `foo` has shape id 2 bar = Bar.new # `bar` has shape id 2 ``` Both `foo` and `bar` instances have the same shape because they both set instance variables of the same name in the same order. This technique can help to improve inline cache hits as well as generate more efficient machine code in JIT compilers. This commit also adds some methods for debugging shapes on objects. See `RubyVM::Shape` for more details. For more context on Object Shapes, see [Feature: #18776] Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org> Co-Authored-By: Eileen M. Uchitelle <eileencodes@gmail.com> Co-Authored-By: John Hawthorn <john@hawthorn.email>
* Add Module#undefined_instance_methodsJeremy Evans2022-06-061-0/+1
| | | | | Implements [Feature #12655] Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
* RCLASS uses FLUSER bits 0 through 3Jemma Issroff2022-05-271-4/+4
|
* Dedup superclass array in leaf sibling classesJohn Hawthorn2022-03-031-1/+2
| | | | | | | | | | | | | | | | Previously, we would build a new `superclasses` array for each class, even though for all immediate subclasses of a class, the array is identical. This avoids duplicating the arrays on leaf classes (those without subclasses) by calculating and storing a "superclasses including self" array on a class when it's first inherited and sharing that among all superclasses. An additional trick used is that the "superclass array including self" is valid as "self"'s superclass array. It just has it's own class at the end. We can use this to avoid an extra pointer of storage and can use one bit of a flag to track that we've "upgraded" the array.
* Constant time class to class ancestor lookupJohn Hawthorn2022-02-231-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | Previously when checking ancestors, we would walk all the way up the ancestry chain checking each parent for a matching class or module. I believe this was especially unfriendly to CPU cache since for each step we need to check two cache lines (the class and class ext). This check is used quite often in: * case statements * rescue statements * Calling protected methods * Class#is_a? * Module#=== * Module#<=> I believe it's most common to check a class against a parent class, to this commit aims to improve that (unfortunately does not help checking for an included Module). This is done by storing on each class the number and an array of all parent classes, in order (BasicObject is at index 0). Using this we can check whether a class is a subclass of another in constant time since we know the location to expect it in the hierarchy.
* Parenthesize the macro argumentNobuyoshi Nakada2022-01-171-1/+1
|
* Separately allocate class_serial on 32-bit systemsPeter Zhu2022-01-141-2/+9
| | | | | | | | On 32-bit systems, VWA causes class_serial to not be aligned (it only guarantees 4 byte alignment but class_serial is 8 bytes and requires 8 byte alignment). This commit uses a hack to allocate class_serial through malloc. Once VWA allocates with 8 byte alignment in the future, we will revert this commit.
* Make RCLASS_EXT(c)->subclasses a doubly linked listMatt Valentine-House2021-11-221-4/+6
| | | | | | | | Updating RCLASS_PARENT_SUBCLASSES and RCLASS_MODULE_SUBCLASSES while compacting can trigger the read barrier. This commit makes RCLASS_SUBCLASSES a doubly linked list with a dedicated head object so that we can add and remove entries from the list without having to touch an object in the Ruby heap
* Remove RCLASS(obj)->ptr when RVARGC is enabledMatt Valentine-House2021-11-111-1/+7
| | | | | | | With RVARGC we always store the rb_classext_t in the same slot as the RClass struct that refers to it. So we don't need to store the pointer or access through the pointer anymore and can switch the RCLASS_EXT macro to use an offset
* Consider modified modules initialized [Bug #18185]Nobuyoshi Nakada2021-09-241-0/+1
|
* Fix a typo [Bug #17048]Nobuyoshi Nakada2021-09-191-1/+1
|
* Already initialized modules cannot be replaced [Bug #17048]Nobuyoshi Nakada2021-09-171-0/+3
|
* internal/*.h: skip doxygen卜部昌平2021-09-101-1/+0
| | | | | These contents are purely implementation details, not worth appearing in CAPI documents. [ci skip]
* Remove old warning aged nearly 8 yearsNobuyoshi Nakada2021-08-191-1/+0
|
* Add a cache for class variableseileencodes2021-06-181-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Redo of 34a2acdac788602c14bf05fb616215187badd504 and 931138b00696419945dc03e10f033b1f53cd50f3 which were reverted. GitHub PR #4340. This change implements a cache for class variables. Previously there was no cache for cvars. Cvar access is slow due to needing to travel all the way up th ancestor tree before returning the cvar value. The deeper the ancestor tree the slower cvar access will be. The benefits of the cache are more visible with a higher number of included modules due to the way Ruby looks up class variables. The benchmark here includes 26 modules and shows with the cache, this branch is 6.5x faster when accessing class variables. ``` compare-ruby: ruby 3.1.0dev (2021-03-15T06:22:34Z master 9e5105c) [x86_64-darwin19] built-ruby: ruby 3.1.0dev (2021-03-15T12:12:44Z add-cache-for-clas.. c6be009) [x86_64-darwin19] | |compare-ruby|built-ruby| |:--------|-----------:|---------:| |vm_cvar | 5.681M| 36.980M| | | -| 6.51x| ``` Benchmark.ips calling `ActiveRecord::Base.logger` from within a Rails application. ActiveRecord::Base.logger has 71 ancestors. The more ancestors a tree has, the more clear the speed increase. IE if Base had only one ancestor we'd see no improvement. This benchmark is run on a vanilla Rails application. Benchmark code: ```ruby require "benchmark/ips" require_relative "config/environment" Benchmark.ips do |x| x.report "logger" do ActiveRecord::Base.logger end end ``` Ruby 3.0 master / Rails 6.1: ``` Warming up -------------------------------------- logger 155.251k i/100ms Calculating ------------------------------------- ``` Ruby 3.0 with cvar cache / Rails 6.1: ``` Warming up -------------------------------------- logger 1.546M i/100ms Calculating ------------------------------------- logger 14.857M (± 4.8%) i/s - 74.198M in 5.006202s ``` Lastly we ran a benchmark to demonstate the difference between master and our cache when the number of modules increases. This benchmark measures 1 ancestor, 30 ancestors, and 100 ancestors. Ruby 3.0 master: ``` Warming up -------------------------------------- 1 module 1.231M i/100ms 30 modules 432.020k i/100ms 100 modules 145.399k i/100ms Calculating ------------------------------------- 1 module 12.210M (± 2.1%) i/s - 61.553M in 5.043400s 30 modules 4.354M (± 2.7%) i/s - 22.033M in 5.063839s 100 modules 1.434M (± 2.9%) i/s - 7.270M in 5.072531s Comparison: 1 module: 12209958.3 i/s 30 modules: 4354217.8 i/s - 2.80x (± 0.00) slower 100 modules: 1434447.3 i/s - 8.51x (± 0.00) slower ``` Ruby 3.0 with cvar cache: ``` Warming up -------------------------------------- 1 module 1.641M i/100ms 30 modules 1.655M i/100ms 100 modules 1.620M i/100ms Calculating ------------------------------------- 1 module 16.279M (± 3.8%) i/s - 82.038M in 5.046923s 30 modules 15.891M (± 3.9%) i/s - 79.459M in 5.007958s 100 modules 16.087M (± 3.6%) i/s - 81.005M in 5.041931s Comparison: 1 module: 16279458.0 i/s 100 modules: 16087484.6 i/s - same-ish: difference falls within error 30 modules: 15891406.2 i/s - same-ish: difference falls within error ``` Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
* Revert "Filling cache values on cvar write"Aaron Patterson2021-05-111-8/+0
| | | | | This reverts commit 08de37f9fa3469365e6b5c964689ae2bae0eb9f3. This reverts commit e8ae922b62adb00a80d3d4c49f7d7b0e6026eaba.
* Add a cache for class variableseileencodes2021-05-111-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This change implements a cache for class variables. Previously there was no cache for cvars. Cvar access is slow due to needing to travel all the way up th ancestor tree before returning the cvar value. The deeper the ancestor tree the slower cvar access will be. The benefits of the cache are more visible with a higher number of included modules due to the way Ruby looks up class variables. The benchmark here includes 26 modules and shows with the cache, this branch is 6.5x faster when accessing class variables. ``` compare-ruby: ruby 3.1.0dev (2021-03-15T06:22:34Z master 9e5105ca45) [x86_64-darwin19] built-ruby: ruby 3.1.0dev (2021-03-15T12:12:44Z add-cache-for-clas.. c6be0093ae) [x86_64-darwin19] | |compare-ruby|built-ruby| |:--------|-----------:|---------:| |vm_cvar | 5.681M| 36.980M| | | -| 6.51x| ``` Benchmark.ips calling `ActiveRecord::Base.logger` from within a Rails application. ActiveRecord::Base.logger has 71 ancestors. The more ancestors a tree has, the more clear the speed increase. IE if Base had only one ancestor we'd see no improvement. This benchmark is run on a vanilla Rails application. Benchmark code: ```ruby require "benchmark/ips" require_relative "config/environment" Benchmark.ips do |x| x.report "logger" do ActiveRecord::Base.logger end end ``` Ruby 3.0 master / Rails 6.1: ``` Warming up -------------------------------------- logger 155.251k i/100ms Calculating ------------------------------------- ``` Ruby 3.0 with cvar cache / Rails 6.1: ``` Warming up -------------------------------------- logger 1.546M i/100ms Calculating ------------------------------------- logger 14.857M (± 4.8%) i/s - 74.198M in 5.006202s ``` Lastly we ran a benchmark to demonstate the difference between master and our cache when the number of modules increases. This benchmark measures 1 ancestor, 30 ancestors, and 100 ancestors. Ruby 3.0 master: ``` Warming up -------------------------------------- 1 module 1.231M i/100ms 30 modules 432.020k i/100ms 100 modules 145.399k i/100ms Calculating ------------------------------------- 1 module 12.210M (± 2.1%) i/s - 61.553M in 5.043400s 30 modules 4.354M (± 2.7%) i/s - 22.033M in 5.063839s 100 modules 1.434M (± 2.9%) i/s - 7.270M in 5.072531s Comparison: 1 module: 12209958.3 i/s 30 modules: 4354217.8 i/s - 2.80x (± 0.00) slower 100 modules: 1434447.3 i/s - 8.51x (± 0.00) slower ``` Ruby 3.0 with cvar cache: ``` Warming up -------------------------------------- 1 module 1.641M i/100ms 30 modules 1.655M i/100ms 100 modules 1.620M i/100ms Calculating ------------------------------------- 1 module 16.279M (± 3.8%) i/s - 82.038M in 5.046923s 30 modules 15.891M (± 3.9%) i/s - 79.459M in 5.007958s 100 modules 16.087M (± 3.6%) i/s - 81.005M in 5.041931s Comparison: 1 module: 16279458.0 i/s 100 modules: 16087484.6 i/s - same-ish: difference falls within error 30 modules: 15891406.2 i/s - same-ish: difference falls within error ``` Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
* Add RCLASS_SUBCLASSES MacroMatt Valentine-House2021-02-011-0/+1
|
* Add RCLASS_ALLOCATOR MacroMatt Valentine-House2021-02-011-0/+1
|
* Add PARENT_MODULE_SUBCLASSES MacroMatt Valentine-House2021-02-011-0/+1
|
* Add RCLASS_PARENT_SUBMODULES MacroMatt Valentine-House2021-02-011-0/+1
|
* sync RClass::ext::iv_index_tblKoichi Sasada2020-10-171-1/+7
| | | | | | | | | | | | iv_index_tbl manages instance variable indexes (ID -> index). This data structure should be synchronized with other ractors so introduce some VM locks. This patch also introduced atomic ivar cache used by set/getinlinecache instructions. To make updating ivar cache (IVC), we changed iv_index_tbl data structure to manage (ID -> entry) and an entry points serial and index. IVC points to this entry so that cache update becomes atomically.
* RClassDeprecated: delete卜部昌平2020-08-271-4/+0
| | | | It has been deprecated for 5 years since 1f2255604087e9a7d7efcb2df61b5ca0e2daa200.
* rb_deprecated_classext_struct: delete卜部昌平2020-08-271-4/+0
| | | | Used from nowhere any longer.
* Remove write barrier exemption for T_ICLASSAlan Wu2020-08-171-0/+6
| | | | | | | | | | | | | | | | | | | Before this commit, iclasses were "shady", or not protected by write barriers. Because of that, the GC needs to spend more time marking these objects than otherwise. Applications that make heavy use of modules should see reduction in GC time as they have a significant number of live iclasses on the heap. - Put logic for iclass method table ownership into a function - Remove calls to WB_UNPROTECT and insert write barriers for iclasses This commit relies on the following invariant: for any non oirigin iclass `I`, `RCLASS_M_TBL(I) == RCLASS_M_TBL(RBasic(I)->klass)`. This invariant did not hold prior to 98286e9 for classes and modules that have prepended modules. [Feature #16984]
* Lazily insert origins on prepend to save memoryAlan Wu2020-07-221-1/+0
| | | | | | | | | | | | | | | | 98286e9850936e27e8ae5e4f20858cc9c13d2dde made it so that `Module#include` allocates an origin iclass on each use. Since `include` is widely used, the extra allocation can contribute significantly to memory usage. Instead of always allocating in anticipation of prepend, this change takes a different approach. The new setup inserts a origin iclass into the super chains of all the children of the module when prepend happens for the first time. rb_ensure_origin is made static again since now that adding an origin now means walking over all usages, we want to limit the number of places where we do it.
* Ensure origins for all included, prepended, and refined modulesJeremy Evans2020-06-031-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes various issues when a module is included in or prepended to a module or class, and then refined, or refined and then included or prepended to a module or class. Implement by renaming ensure_origin to rb_ensure_origin, making it non-static, and calling it when refining a module. Fix Module#initialize_copy to handle origins correctly. Previously, Module#initialize_copy did not handle origins correctly. For example, this code: ```ruby module B; end class A def b; 2 end prepend B end a = A.dup.new class A def b; 1 end end p a.b ``` Printed 1 instead of 2. This is because the super chain for a.singleton_class was: ``` a.singleton_class A.dup B(iclass) B(iclass origin) A(origin) # not A.dup(origin) ``` The B iclasses would not be modified, so the includer entry would be still be set to A and not A.dup. This modifies things so that if the class/module has an origin, all iclasses between the class/module and the origin are duplicated and have the correct includer entry set, and the correct origin is created. This requires other changes to make sure all tests still pass: * rb_undef_methods_from doesn't automatically handle classes with origins, so pass it the origin for Comparable when undefing methods in Complex. This fixed a failure in the Complex tests. * When adding a method, the method cache was not cleared correctly if klass has an origin. Clear the method cache for the klass before switching to the origin of klass. This fixed failures in the autoload tests related to overridding require, without breaking the optimization tests. Also clear the method cache for both the module and origin when removing a method. * Module#include? is fixed to skip origin iclasses. * Refinements are fixed to use the origin class of the module that has an origin. * RCLASS_REFINED_BY_ANY is removed as it was only used in a single place and is no longer needed. * Marshal#dump is fixed to skip iclass origins. * rb_method_entry_make is fixed to handled overridden optimized methods for modules that have origins. Fixes [Bug #16852]
* Fix origin iclass pointer for modulesJeremy Evans2020-05-221-1/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If a module has an origin, and that module is included in another module or class, previously the iclass created for the module had an origin pointer to the module's origin instead of the iclass's origin. Setting the origin pointer correctly requires using a stack, since the origin iclass is not created until after the iclass itself. Use a hidden ruby array to implement that stack. Correctly assigning the origin pointers in the iclass caused a use-after-free in GC. If a module with an origin is included in a class, the iclass shares a method table with the module and the iclass origin shares a method table with module origin. Mark iclass origin with a flag that notes that even though the iclass is an origin, it shares a method table, so the method table should not be garbage collected. The shared method table will be garbage collected when the module origin is garbage collected. I've tested that this does not introduce a memory leak. This change caused a VM assertion failure, which was traced to callable method entries using the incorrect defined_class. Update rb_vm_check_redefinition_opt_method and find_defined_class_by_owner to treat iclass origins different than class origins to avoid this issue. This also includes a fix for Module#included_modules to skip iclasses with origins. Fixes [Bug #16736]