Skip to content

Implement class hierarchy method caching #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 23, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 134 additions & 16 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,109 @@
extern st_table *rb_class_tbl;
static ID id_attached;

void
rb_class_subclass_add(VALUE super, VALUE klass)
{
rb_subclass_entry_t *entry, *head;

if (super && super != Qundef) {
entry = malloc(sizeof(*entry));
entry->klass = klass;
entry->next = NULL;

head = RCLASS_EXT(super)->subclasses;
if (head) {
entry->next = head;
RCLASS_EXT(head->klass)->parent_subclasses = &entry->next;
}

RCLASS_EXT(super)->subclasses = entry;
RCLASS_EXT(klass)->parent_subclasses = &RCLASS_EXT(super)->subclasses;
}
}

static void
rb_module_add_to_subclasses_list(VALUE module, VALUE iclass)
{
rb_subclass_entry_t *entry, *head;

entry = malloc(sizeof(*entry));
entry->klass = iclass;
entry->next = NULL;

head = RCLASS_EXT(module)->subclasses;
if (head) {
entry->next = head;
RCLASS_EXT(head->klass)->module_subclasses = &entry->next;
}

RCLASS_EXT(module)->subclasses = entry;
RCLASS_EXT(iclass)->module_subclasses = &RCLASS_EXT(module)->subclasses;
}

void
rb_class_remove_from_super_subclasses(VALUE klass)
{
rb_subclass_entry_t *entry;

if (RCLASS_EXT(klass)->parent_subclasses) {
entry = *RCLASS_EXT(klass)->parent_subclasses;

*RCLASS_EXT(klass)->parent_subclasses = entry->next;
if (entry->next) {
RCLASS_EXT(entry->next->klass)->parent_subclasses = RCLASS_EXT(klass)->parent_subclasses;
}
free(entry);
}

RCLASS_EXT(klass)->parent_subclasses = NULL;
}

void
rb_class_remove_from_module_subclasses(VALUE klass)
{
rb_subclass_entry_t *entry;

if (RCLASS_EXT(klass)->module_subclasses) {
entry = *RCLASS_EXT(klass)->module_subclasses;
*RCLASS_EXT(klass)->module_subclasses = entry->next;

if (entry->next) {
RCLASS_EXT(entry->next->klass)->module_subclasses = RCLASS_EXT(klass)->module_subclasses;
}

free(entry);
}

RCLASS_EXT(klass)->module_subclasses = NULL;
}

void
rb_class_foreach_subclass(VALUE klass, void(*f)(VALUE))
{
rb_subclass_entry_t *cur = RCLASS_EXT(klass)->subclasses;

/* do not be tempted to simplify this loop into a for loop, the order of
operations is important here if `f` modifies the linked list */
while (cur) {
VALUE curklass = cur->klass;
cur = cur->next;
f(curklass);
}
}

void
rb_class_detach_subclasses(VALUE klass)
{
rb_class_foreach_subclass(klass, rb_class_remove_from_super_subclasses);
}

void
rb_class_detach_module_subclasses(VALUE klass)
{
rb_class_foreach_subclass(klass, rb_class_remove_from_module_subclasses);
}

/**
* Allocates a struct RClass for a new class.
*
Expand All @@ -54,9 +157,15 @@ class_alloc(VALUE flags, VALUE klass)
RCLASS_IV_TBL(obj) = 0;
RCLASS_CONST_TBL(obj) = 0;
RCLASS_M_TBL(obj) = 0;
RCLASS_SUPER(obj) = 0;
RCLASS_SET_SUPER((VALUE)obj, 0);
RCLASS_ORIGIN(obj) = (VALUE)obj;
RCLASS_IV_INDEX_TBL(obj) = 0;

RCLASS_EXT(obj)->subclasses = NULL;
RCLASS_EXT(obj)->parent_subclasses = NULL;
RCLASS_EXT(obj)->module_subclasses = NULL;
RCLASS_EXT(obj)->seq = rb_next_class_sequence();

RCLASS_REFINED_CLASS(obj) = Qnil;
RCLASS_EXT(obj)->allocator = 0;
return (VALUE)obj;
Expand All @@ -77,7 +186,7 @@ rb_class_boot(VALUE super)
{
VALUE klass = class_alloc(T_CLASS, rb_cClass);

RCLASS_SUPER(klass) = super;
RCLASS_SET_SUPER(klass, super);
RCLASS_M_TBL(klass) = st_init_numtable();

OBJ_INFECT(klass, super);
Expand Down Expand Up @@ -203,7 +312,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
RBASIC(clone)->klass = rb_singleton_class_clone(orig);
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
}
RCLASS_SUPER(clone) = RCLASS_SUPER(orig);
RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig));
RCLASS_EXT(clone)->allocator = RCLASS_EXT(orig)->allocator;
if (RCLASS_IV_TBL(orig)) {
st_data_t id;
Expand Down Expand Up @@ -261,7 +370,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
RBASIC(clone)->klass = rb_singleton_class_clone(klass);
}

RCLASS_SUPER(clone) = RCLASS_SUPER(klass);
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
RCLASS_EXT(clone)->allocator = RCLASS_EXT(klass)->allocator;
if (RCLASS_IV_TBL(klass)) {
RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(klass));
Expand Down Expand Up @@ -356,7 +465,7 @@ make_metaclass(VALUE klass)

super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
RCLASS_SUPER(metaclass) = super ? ENSURE_EIGENCLASS(super) : rb_cClass;
RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);

OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));

Expand Down Expand Up @@ -676,7 +785,7 @@ rb_include_class_new(VALUE module, VALUE super)
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
RCLASS_M_TBL(klass) = RCLASS_M_TBL(RCLASS_ORIGIN(module));
RCLASS_SUPER(klass) = super;
RCLASS_SET_SUPER(klass, super);
if (RB_TYPE_P(module, T_ICLASS)) {
RBASIC(klass)->klass = RBASIC(module)->klass;
}
Expand Down Expand Up @@ -710,7 +819,6 @@ rb_include_module(VALUE klass, VALUE module)
changed = include_modules_at(klass, RCLASS_ORIGIN(klass), module);
if (changed < 0)
rb_raise(rb_eArgError, "cyclic include detected");
if (changed) rb_clear_cache();
}

static int
Expand All @@ -723,8 +831,8 @@ add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
static int
include_modules_at(const VALUE klass, VALUE c, VALUE module)
{
VALUE p;
int changed = 0;
VALUE p, iclass;
int method_changed = 0, constant_changed = 0;
const st_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));

while (module) {
Expand All @@ -750,7 +858,15 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
break;
}
}
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
iclass = rb_include_class_new(module, RCLASS_SUPER(c));
c = RCLASS_SET_SUPER(c, iclass);

if (BUILTIN_TYPE(module) == T_ICLASS) {
rb_module_add_to_subclasses_list(RBASIC(module)->klass, iclass);
} else {
rb_module_add_to_subclasses_list(module, iclass);
}

if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
VALUE refined_class =
rb_refinement_module_get_refined_class(klass);
Expand All @@ -760,14 +876,17 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
FL_SET(c, RMODULE_INCLUDED_INTO_REFINEMENT);
}
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
changed = 1;
method_changed = 1;
if (RMODULE_CONST_TBL(module) && RMODULE_CONST_TBL(module)->num_entries)
changed = 1;
constant_changed = 1;
skip:
module = RCLASS_SUPER(module);
}

return changed;
if (method_changed) rb_clear_cache_by_class(klass);
if (constant_changed) rb_clear_cache();

return method_changed;
}

static int
Expand Down Expand Up @@ -816,8 +935,8 @@ rb_prepend_module(VALUE klass, VALUE module)
origin = RCLASS_ORIGIN(klass);
if (origin == klass) {
origin = class_alloc(T_ICLASS, klass);
RCLASS_SUPER(origin) = RCLASS_SUPER(klass);
RCLASS_SUPER(klass) = origin;
RCLASS_SET_SUPER(origin, RCLASS_SUPER(klass));
RCLASS_SET_SUPER(klass, origin);
RCLASS_ORIGIN(klass) = origin;
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL(klass) = st_init_numtable();
Expand All @@ -828,7 +947,6 @@ rb_prepend_module(VALUE klass, VALUE module)
if (changed < 0)
rb_raise(rb_eArgError, "cyclic prepend detected");
if (changed) {
rb_clear_cache();
rb_vm_check_redefinition_by_prepend(klass);
}
}
Expand Down
1 change: 1 addition & 0 deletions compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,7 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, VALUE block, unsigned long flag)
}
}
ci->vmstat = 0;
ci->seq = 0;
ci->blockptr = 0;
ci->recv = Qundef;
ci->call = 0; /* TODO: should set default function? */
Expand Down
10 changes: 5 additions & 5 deletions eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ rb_using_refinement(NODE *cref, VALUE klass, VALUE module)
module = RCLASS_SUPER(module);
while (module && module != klass) {
FL_SET(module, RMODULE_IS_OVERLAID);
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
c = RCLASS_SET_SUPER(c, rb_include_class_new(module, RCLASS_SUPER(c)));
RCLASS_REFINED_CLASS(c) = klass;
module = RCLASS_SUPER(module);
}
Expand Down Expand Up @@ -1156,8 +1156,8 @@ add_activated_refinement(VALUE activated_refinements,
refinement = RCLASS_SUPER(refinement);
while (refinement) {
FL_SET(refinement, RMODULE_IS_OVERLAID);
c = RCLASS_SUPER(c) =
rb_include_class_new(refinement, RCLASS_SUPER(c));
c = RCLASS_SET_SUPER(c,
rb_include_class_new(refinement, RCLASS_SUPER(c)));
RCLASS_REFINED_CLASS(c) = klass;
refinement = RCLASS_SUPER(refinement);
}
Expand Down Expand Up @@ -1210,7 +1210,7 @@ rb_mod_refine(VALUE module, VALUE klass)
refinement = rb_hash_lookup(refinements, klass);
if (NIL_P(refinement)) {
refinement = rb_module_new();
RCLASS_SUPER(refinement) = klass;
RCLASS_SET_SUPER(refinement, klass);
FL_SET(refinement, RMODULE_IS_REFINEMENT);
CONST_ID(id_refined_class, "__refined_class__");
rb_ivar_set(refinement, id_refined_class, klass);
Expand Down Expand Up @@ -1356,7 +1356,7 @@ top_using(VALUE self, VALUE module)
}
Check_Type(module, T_MODULE);
rb_using_module(cref, module);
rb_clear_cache();
rb_clear_cache_by_class(rb_cObject);
return self;
}

Expand Down
24 changes: 21 additions & 3 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,6 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
break;
case T_MODULE:
case T_CLASS:
rb_clear_cache_by_class((VALUE)obj);
if (RCLASS_M_TBL(obj)) {
rb_free_m_table(RCLASS_M_TBL(obj));
}
Expand All @@ -943,7 +942,19 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
if (RCLASS_IV_INDEX_TBL(obj)) {
st_free_table(RCLASS_IV_INDEX_TBL(obj));
}
xfree(RANY(obj)->as.klass.ptr);
if (RCLASS_EXT(obj)->subclasses) {
if (BUILTIN_TYPE(obj) == T_MODULE) {
rb_class_detach_module_subclasses(obj);
} else {
rb_class_detach_subclasses(obj);
}
RCLASS_EXT(obj)->subclasses = NULL;
}
rb_class_remove_from_module_subclasses(obj);
rb_class_remove_from_super_subclasses(obj);
if (RANY(obj)->as.klass.ptr)
xfree(RANY(obj)->as.klass.ptr);
RANY(obj)->as.klass.ptr = NULL;
break;
case T_STRING:
rb_str_free(obj);
Expand Down Expand Up @@ -995,7 +1006,14 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
break;
case T_ICLASS:
/* iClass shares table with the module */
if (RCLASS_EXT(obj)->subclasses) {
rb_class_detach_subclasses(obj);
RCLASS_EXT(obj)->subclasses = NULL;
}
rb_class_remove_from_module_subclasses(obj);
rb_class_remove_from_super_subclasses(obj);
xfree(RANY(obj)->as.klass.ptr);
RANY(obj)->as.klass.ptr = NULL;
break;

case T_FLOAT:
Expand Down Expand Up @@ -2792,7 +2810,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
if (!RCLASS_EXT(obj)) break;
mark_tbl(objspace, RCLASS_IV_TBL(obj));
mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
ptr = RCLASS_SUPER(obj);
ptr = RCLASS_SUPER((VALUE)obj);
goto again;

case T_ARRAY:
Expand Down
4 changes: 2 additions & 2 deletions insns.def
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ setconstant
{
vm_check_if_namespace(cbase);
rb_const_set(cbase, id, val);
INC_VM_STATE_VERSION();
rb_clear_cache_by_class(cbase);
}

/**
Expand Down Expand Up @@ -975,7 +975,7 @@ defineclass
class_iseq->local_size, 0);
RESTORE_REGS();

INC_VM_STATE_VERSION();
rb_clear_cache_by_class(klass);
NEXT_INSN();
}

Expand Down
Loading