зеркало из https://github.com/github/ruby.git
Lazily insert origins on prepend to save memory
98286e9850
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.
This commit is contained in:
Родитель
fdcbb288ab
Коммит
37e6c83609
26
class.c
26
class.c
|
@ -348,6 +348,8 @@ copy_tables(VALUE clone, VALUE orig)
|
|||
}
|
||||
}
|
||||
|
||||
static void ensure_origin(VALUE klass);
|
||||
|
||||
/* :nodoc: */
|
||||
VALUE
|
||||
rb_mod_init_copy(VALUE clone, VALUE orig)
|
||||
|
@ -390,7 +392,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
|
|||
int add_subclass;
|
||||
VALUE clone_origin;
|
||||
|
||||
rb_ensure_origin(clone);
|
||||
ensure_origin(clone);
|
||||
clone_origin = RCLASS_ORIGIN(clone);
|
||||
|
||||
while (p && p != orig_origin) {
|
||||
|
@ -999,8 +1001,6 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
|
|||
struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));
|
||||
VALUE original_klass = klass;
|
||||
|
||||
rb_ensure_origin(module);
|
||||
|
||||
while (module) {
|
||||
int superclass_seen = FALSE;
|
||||
struct rb_id_table *tbl;
|
||||
|
@ -1112,8 +1112,8 @@ move_refined_method(ID key, VALUE value, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_ensure_origin(VALUE klass)
|
||||
static void
|
||||
ensure_origin(VALUE klass)
|
||||
{
|
||||
VALUE origin = RCLASS_ORIGIN(klass);
|
||||
if (origin == klass) {
|
||||
|
@ -1132,9 +1132,10 @@ void
|
|||
rb_prepend_module(VALUE klass, VALUE module)
|
||||
{
|
||||
int changed = 0;
|
||||
bool klass_had_no_origin = RCLASS_ORIGIN(klass) == klass;
|
||||
|
||||
ensure_includable(klass, module);
|
||||
rb_ensure_origin(klass);
|
||||
ensure_origin(klass);
|
||||
changed = include_modules_at(klass, klass, module, FALSE);
|
||||
if (changed < 0)
|
||||
rb_raise(rb_eArgError, "cyclic prepend detected");
|
||||
|
@ -1143,7 +1144,20 @@ rb_prepend_module(VALUE klass, VALUE module)
|
|||
}
|
||||
if (RB_TYPE_P(klass, T_MODULE)) {
|
||||
rb_subclass_entry_t *iclass = RCLASS_EXT(klass)->subclasses;
|
||||
VALUE klass_origin = RCLASS_ORIGIN(klass);
|
||||
struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass);
|
||||
struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin);
|
||||
while (iclass) {
|
||||
if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(iclass->klass)) {
|
||||
// backfill an origin iclass to handle refinements and future prepends
|
||||
rb_id_table_foreach(RCLASS_M_TBL(iclass->klass), clear_module_cache_i, (void *)iclass->klass);
|
||||
RCLASS_M_TBL(iclass->klass) = klass_m_tbl;
|
||||
VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(iclass->klass));
|
||||
RCLASS_SET_SUPER(iclass->klass, origin);
|
||||
RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(iclass->klass));
|
||||
RCLASS_SET_ORIGIN(iclass->klass, origin);
|
||||
RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
|
||||
}
|
||||
include_modules_at(iclass->klass, iclass->klass, module, FALSE);
|
||||
iclass = iclass->next;
|
||||
}
|
||||
|
|
3
eval.c
3
eval.c
|
@ -1551,9 +1551,6 @@ rb_mod_refine(VALUE module, VALUE klass)
|
|||
}
|
||||
|
||||
ensure_class_or_module(klass);
|
||||
if (RB_TYPE_P(klass, T_MODULE)) {
|
||||
rb_ensure_origin(klass);
|
||||
}
|
||||
CONST_ID(id_refinements, "__refinements__");
|
||||
refinements = rb_attr_get(module, id_refinements);
|
||||
if (NIL_P(refinements)) {
|
||||
|
|
|
@ -119,7 +119,6 @@ VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach);
|
|||
VALUE rb_singleton_class_get(VALUE obj);
|
||||
int rb_class_has_methods(VALUE c);
|
||||
void rb_undef_methods_from(VALUE klass, VALUE super);
|
||||
void rb_ensure_origin(VALUE klass);
|
||||
|
||||
static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
|
||||
static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass);
|
||||
|
|
Загрузка…
Ссылка в новой задаче