Skip to content
Browse files

use sparse array for method cache instead of global cache

  • Loading branch information...
1 parent 57bc8b7 commit e92af09aed54f47700919b9d3ecf6e022eb3ef0f @funny-falcon committed Sep 1, 2012
Showing with 42 additions and 38 deletions.
  1. +6 −0 class.c
  2. +4 −0 gc.c
  3. +2 −0 include/ruby/ruby.h
  4. +5 −0 internal.h
  5. +25 −38 vm_method.c
View
6 class.c
@@ -50,18 +50,24 @@ static VALUE
class_alloc(VALUE flags, VALUE klass)
{
rb_classext_t *ext = ALLOC(rb_classext_t);
+ rb_class_cache_t *cache = ALLOC(rb_class_cache_t);
NEWOBJ(obj, struct RClass);
OBJSETUP(obj, klass, flags);
obj->ptr = ext;
+ obj->cache = cache;
MEMZERO(ext, struct rb_classext_struct, 1);
+ MEMZERO(cache, struct rb_class_cache_struct, 1);
return (VALUE)obj;
}
static VALUE
iclass_alloc()
{
+ rb_class_cache_t *cache = ALLOC(rb_class_cache_t);
NEWOBJ(obj, struct RClass);
OBJSETUP(obj, rb_cClass, T_ICLASS);
+ obj->cache = cache;
+ MEMZERO(cache, struct rb_class_cache_struct, 1);
return (VALUE)obj;
}
View
4 gc.c
@@ -2385,6 +2385,8 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
sa_clear(RCLASS_IV_TBL(obj));
rb_free_const_table(RCLASS_CONST_TBL(obj));
sa_clear(RCLASS_IV_INDEX_TBL(obj));
+ sa_clear(&RCLASS(obj)->cache->m_cache_tbl);
+ xfree(RCLASS(obj)->cache);
xfree(RANY(obj)->as.klass.ptr);
break;
case T_STRING:
@@ -2436,6 +2438,8 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case T_COMPLEX:
break;
case T_ICLASS:
+ sa_clear(&RCLASS(obj)->cache->m_cache_tbl);
+ xfree(RCLASS(obj)->cache);
/* iClass shares table with the module */
break;
View
2 include/ruby/ruby.h
@@ -626,11 +626,13 @@ struct RObject {
/** @internal */
typedef struct rb_classext_struct rb_classext_t;
+typedef struct rb_class_cache_struct rb_class_cache_t;
struct RClass {
struct RBasic basic;
VALUE super;
rb_classext_t *ptr;
+ rb_class_cache_t *cache;
};
#define RCLASS_SUPER(c) rb_class_get_superclass(c)
#define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
View
5 internal.h
@@ -30,6 +30,11 @@ struct rb_classext_struct {
sa_table iv_index_tbl;
};
+struct rb_class_cache_struct {
+ VALUE method_cache_version;
+ sa_table m_cache_tbl;
+};
+
#undef RCLASS_SUPER
#define RCLASS_EXT(c) (RCLASS(c)->ptr)
#define RCLASS_SUPER(c) (RCLASS(c)->super)
View
63 vm_method.c
@@ -2,38 +2,33 @@
* This file is included by vm.c
*/
-#define CACHE_SIZE 0x800
-#define CACHE_MASK 0x7ff
-#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
-
static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me);
static ID object_id, respond_to_missing;
static ID removed, singleton_removed, undefined, singleton_undefined;
static ID added, singleton_added, attached;
-struct cache_entry { /* method hash table. */
- VALUE filled_version; /* filled state version */
- ID mid; /* method's id */
- VALUE klass; /* receiver's class */
- rb_method_entry_t *me;
-};
-
-static struct cache_entry cache[CACHE_SIZE];
#define ruby_running (GET_VM()->running)
/* int ruby_running = 0; */
+static int
+methods_cache_clear_callback(void *vstart, void *vend, size_t stride, void *data)
+{
+ VALUE v = (VALUE)vstart;
+ for (; v != (VALUE)vend; v += stride) {
+ switch(BUILTIN_TYPE(v)) {
+ case T_CLASS:
+ case T_MODULE:
+ case T_ICLASS:
+ RCLASS(v)->cache->method_cache_version = 0;
+ }
+ }
+ return 0;
+}
static void
vm_clear_global_method_cache(void)
{
- struct cache_entry *ent, *end;
-
- ent = cache;
- end = ent + CACHE_SIZE;
- while (ent < end) {
- ent->filled_version = 0;
- ent++;
- }
+ rb_objspace_each_objects(methods_cache_clear_callback, NULL);
}
void
@@ -393,20 +388,10 @@ rb_method_entry_get_without_cache(VALUE klass, ID id)
rb_method_entry_t *me = search_method(klass, id);
if (ruby_running) {
- struct cache_entry *ent;
- ent = cache + EXPR1(klass, id);
- ent->filled_version = GET_VM_STATE_VERSION();
- ent->klass = klass;
-
if (UNDEFINED_METHOD_ENTRY_P(me)) {
- ent->mid = id;
- ent->me = 0;
- me = 0;
- }
- else {
- ent->mid = id;
- ent->me = me;
+ me = 0;
}
+ sa_insert(&RCLASS(klass)->cache->m_cache_tbl, (sa_index_t)id, (st_data_t)me);
}
return me;
@@ -415,14 +400,16 @@ rb_method_entry_get_without_cache(VALUE klass, ID id)
rb_method_entry_t *
rb_method_entry(VALUE klass, ID id)
{
- struct cache_entry *ent;
+ rb_class_cache_t *cache = RCLASS(klass)->cache;
+ rb_method_entry_t *me;
- ent = cache + EXPR1(klass, id);
- if (ent->filled_version == GET_VM_STATE_VERSION() &&
- ent->mid == id && ent->klass == klass) {
- return ent->me;
+ if (cache->method_cache_version != GET_VM_STATE_VERSION()) {
+ sa_clear_no_free(&cache->m_cache_tbl);
+ cache->method_cache_version = GET_VM_STATE_VERSION();
+ }
+ else if (sa_lookup(&cache->m_cache_tbl, (sa_index_t)id, (st_data_t*)&me)) {
+ return me;
}
-
return rb_method_entry_get_without_cache(klass, id);
}

0 comments on commit e92af09

Please sign in to comment.
Something went wrong with that request. Please try again.