Currently, iclasses were are "shady", or not protected by write barriers. Because of that, the GC needs to spend more time marking these objects than otherwise. Let's insert write barriers for iclasses. Applications that make heavy use of modules heavily 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 The change relies on the following invariant: for any 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. --- Patch: Code: https://github.com/ruby/ruby/pull/3410 This is the second version of this change. It's much simpler and it doesn't introduce new garbage collected objects. I realized that despite saving a pointer to some other object's method table, iclasses don't mark the method tables. So, for each method table, there is an unique object that's responsible for marking it. Since write barriers are only needed for the object that is marking the newly written value (correct me if if I'm wrong here), having an unique object that marks the tables makes things straight forward. The numbers from v1 of this patch was a bit inflated because we were [allocating an excessive amount of iclasses](https://github.com/ruby/ruby/commit/37e6c83609ac9d4c30ca4660ee16701e53cf82a3) so measured again. An app that has an approximately 250MiB heap saw a 22% reduction in minor GC time. Credits to @tenderlovemaking for motivating this change.