diff options
-rw-r--r-- | ChangeLog | 21 | ||||
-rw-r--r-- | class.c | 4 | ||||
-rw-r--r-- | compile.c | 2 | ||||
-rw-r--r-- | eval.c | 4 | ||||
-rw-r--r-- | include/ruby/intern.h | 3 | ||||
-rw-r--r-- | insns.def | 7 | ||||
-rw-r--r-- | variable.c | 12 | ||||
-rw-r--r-- | vm.c | 11 | ||||
-rw-r--r-- | vm_core.h | 2 | ||||
-rw-r--r-- | vm_insnhelper.c | 6 | ||||
-rw-r--r-- | vm_insnhelper.h | 8 | ||||
-rw-r--r-- | vm_method.c | 32 |
12 files changed, 70 insertions, 42 deletions
@@ -1,3 +1,24 @@ +Tue Oct 29 09:53:00 2013 Charlie Somerville <charliesome@ruby-lang.org> + + * insns.def, vm.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: split + ruby_vm_global_state_version into two separate counters - one for the + global method state and one for the global constant state. This means + changes to constants do not affect method caches, and changes to + methods do not affect constant caches. In particular, this means + inclusions of modules containing constants no longer globally + invalidate the method cache. + + * class.c, eval.c, include/ruby/intern.h, insns.def, vm.c, vm_method.c: + rename rb_clear_cache_by_class to rb_clear_method_cache_by_class + + * class.c, include/ruby/intern.h, variable.c, vm_method.c: add + rb_clear_constant_cache + + * compile.c, vm_core.h, vm_insnhelper.c: rename vmstat field in + rb_call_info_struct to method_state + + * vm_method.c: rename vmstat field in struct cache_entry to method_state + Mon Oct 28 23:26:04 2013 Tanaka Akira <akr@fsij.org> * test/readline/test_readline.rb (teardown): Clear Readline.input and @@ -900,8 +900,8 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module) module = RCLASS_SUPER(module); } - if (method_changed) rb_clear_cache_by_class(klass); - if (constant_changed) rb_clear_cache(); + if (method_changed) rb_clear_method_cache_by_class(klass); + if (constant_changed) rb_clear_constant_cache(); return method_changed; } @@ -961,7 +961,7 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, VALUE block, unsigned long flag) ci->flag |= VM_CALL_ARGS_SKIP_SETUP; } } - ci->vmstat = 0; + ci->method_state = 0; ci->seq = 0; ci->blockptr = 0; ci->recv = Qundef; @@ -1263,7 +1263,7 @@ mod_using(VALUE self, VALUE module) } Check_Type(module, T_MODULE); rb_using_module(cref, module); - rb_clear_cache_by_class(rb_cObject); + rb_clear_method_cache_by_class(rb_cObject); return self; } @@ -1399,7 +1399,7 @@ top_using(VALUE self, VALUE module) } Check_Type(module, T_MODULE); rb_using_module(cref, module); - rb_clear_cache_by_class(rb_cObject); + rb_clear_method_cache_by_class(rb_cObject); return self; } diff --git a/include/ruby/intern.h b/include/ruby/intern.h index fa0c075b83..b294f2d0fa 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -376,7 +376,8 @@ void rb_define_alloc_func(VALUE, rb_alloc_func_t); void rb_undef_alloc_func(VALUE); rb_alloc_func_t rb_get_alloc_func(VALUE); void rb_clear_cache(void); -void rb_clear_cache_by_class(VALUE); +void rb_clear_constant_cache(void); +void rb_clear_method_cache_by_class(VALUE); void rb_alias(VALUE, ID, ID); void rb_attr(VALUE,ID,int,int,int); int rb_method_boundp(VALUE, ID, int); @@ -218,7 +218,6 @@ setconstant { vm_check_if_namespace(cbase); rb_const_set(cbase, id, val); - rb_clear_cache_by_class(cbase); } /** @@ -974,8 +973,6 @@ defineclass class_iseq->iseq_encoded, GET_SP(), class_iseq->local_size, 0, class_iseq->stack_max); RESTORE_REGS(); - - rb_clear_cache_by_class(klass); NEXT_INSN(); } @@ -1186,7 +1183,7 @@ getinlinecache () (VALUE val) { - if (ic->ic_vmstat == GET_VM_STATE_VERSION()) { + if (ic->ic_vmstat == GET_CONSTANT_STATE_VERSION()) { val = ic->ic_value.value; JUMP(dst); } @@ -1211,7 +1208,7 @@ setinlinecache rb_iseq_add_mark_object(GET_ISEQ(), val); } ic->ic_value.value = val; - ic->ic_vmstat = GET_VM_STATE_VERSION() - ruby_vm_const_missing_count; + ic->ic_vmstat = GET_CONSTANT_STATE_VERSION() - ruby_vm_const_missing_count; ruby_vm_const_missing_count = 0; } diff --git a/variable.c b/variable.c index 9da4ee217d..d07f9ff9dd 100644 --- a/variable.c +++ b/variable.c @@ -1941,7 +1941,7 @@ rb_const_remove(VALUE mod, ID id) rb_class_name(mod), QUOTE_ID(id)); } - rb_clear_cache(); + rb_clear_constant_cache(); val = ((rb_const_entry_t*)v)->value; if (val == Qundef) { @@ -2151,7 +2151,7 @@ rb_const_set(VALUE klass, ID id, VALUE val) load = autoload_data(klass, id); /* for autoloading thread, keep the defined value to autoloading storage */ if (load && (ele = check_autoload_data(load)) && (ele->thread == rb_thread_current())) { - rb_clear_cache(); + rb_clear_constant_cache(); ele->value = val; /* autoload_i is shady */ return; @@ -2175,7 +2175,7 @@ rb_const_set(VALUE klass, ID id, VALUE val) } } - rb_clear_cache(); + rb_clear_constant_cache(); ce = ALLOC(rb_const_entry_t); @@ -2222,7 +2222,7 @@ set_const_visibility(VALUE mod, int argc, VALUE *argv, rb_const_flag_t flag) id = rb_check_id(&val); if (!id) { if (i > 0) { - rb_clear_cache(); + rb_clear_constant_cache(); } rb_name_error_str(val, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined", @@ -2234,13 +2234,13 @@ set_const_visibility(VALUE mod, int argc, VALUE *argv, rb_const_flag_t flag) } else { if (i > 0) { - rb_clear_cache(); + rb_clear_constant_cache(); } rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined", rb_class_name(mod), QUOTE_ID(id)); } } - rb_clear_cache(); + rb_clear_constant_cache(); } /* @@ -71,7 +71,8 @@ static VALUE vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, int argc, const VALUE *argv, const rb_block_t *blockptr); -static vm_state_version_t ruby_vm_global_state_version = 1; +static vm_state_version_t ruby_vm_method_state_version = 1; +static vm_state_version_t ruby_vm_constant_state_version = 1; static vm_state_version_t ruby_vm_sequence = 1; #include "vm_insnhelper.h" @@ -2075,12 +2076,12 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, OBJ_WRITE(miseq->self, &miseq->klass, klass); miseq->defined_method_id = id; rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex); - rb_clear_cache_by_class(klass); + rb_clear_method_cache_by_class(klass); if (!is_singleton && noex == NOEX_MODFUNC) { klass = rb_singleton_class(klass); rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC); - rb_clear_cache_by_class(klass); + rb_clear_method_cache_by_class(klass); } } @@ -2130,8 +2131,8 @@ m_core_undef_method(VALUE self, VALUE cbase, VALUE sym) { REWIND_CFP({ rb_undef(cbase, SYM2ID(sym)); - rb_clear_cache_by_class(cbase); - rb_clear_cache_by_class(self); + rb_clear_method_cache_by_class(cbase); + rb_clear_method_cache_by_class(self); }); return Qnil; } @@ -162,7 +162,7 @@ typedef struct rb_call_info_struct { rb_iseq_t *blockiseq; /* inline cache: keys */ - vm_state_version_t vmstat; + vm_state_version_t method_state; vm_state_version_t seq; VALUE klass; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 8fd6b1ef27..91e9142cb9 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -846,7 +846,7 @@ vm_search_method(rb_call_info_t *ci, VALUE recv) VALUE klass = CLASS_OF(recv); #if OPT_INLINE_METHOD_CACHE - if (LIKELY(GET_VM_STATE_VERSION() == ci->vmstat && RCLASS_EXT(klass)->seq == ci->seq)) { + if (LIKELY(GET_METHOD_STATE_VERSION() == ci->method_state && RCLASS_EXT(klass)->seq == ci->seq)) { /* cache hit! */ return; } @@ -856,7 +856,7 @@ vm_search_method(rb_call_info_t *ci, VALUE recv) ci->klass = klass; ci->call = vm_call_general; #if OPT_INLINE_METHOD_CACHE - ci->vmstat = GET_VM_STATE_VERSION(); + ci->method_state = GET_METHOD_STATE_VERSION(); ci->seq = RCLASS_EXT(klass)->seq; #endif } @@ -924,7 +924,7 @@ rb_equal_opt(VALUE obj1, VALUE obj2) rb_call_info_t ci; ci.mid = idEq; ci.klass = 0; - ci.vmstat = 0; + ci.method_state = 0; ci.me = NULL; ci.defined_class = 0; return opt_eq_func(obj1, obj2, &ci); diff --git a/vm_insnhelper.h b/vm_insnhelper.h index 1c0d046587..674e6cad64 100644 --- a/vm_insnhelper.h +++ b/vm_insnhelper.h @@ -260,10 +260,10 @@ enum vm_regan_acttype { } while (0) #define NEXT_CLASS_SEQUENCE() (++ruby_vm_sequence) -#define GET_VM_STATE_VERSION() (ruby_vm_global_state_version) -#define INC_VM_STATE_VERSION() do { \ - ruby_vm_global_state_version = (ruby_vm_global_state_version + 1); \ -} while (0) +#define GET_METHOD_STATE_VERSION() (ruby_vm_method_state_version) +#define INC_METHOD_STATE_VERSION() (++ruby_vm_method_state_version) +#define GET_CONSTANT_STATE_VERSION() (ruby_vm_constant_state_version) +#define INC_CONSTANT_STATE_VERSION() (++ruby_vm_constant_state_version) static VALUE make_no_method_exception(VALUE exc, const char *format, VALUE obj, int argc, const VALUE *argv); diff --git a/vm_method.c b/vm_method.c index 30bd6b6a1f..239f8b2874 100644 --- a/vm_method.c +++ b/vm_method.c @@ -25,7 +25,7 @@ static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VAL #define attached id__attached__ struct cache_entry { - vm_state_version_t vm_state; + vm_state_version_t method_state; vm_state_version_t seq; ID mid; rb_method_entry_t* me; @@ -46,15 +46,23 @@ rb_class_clear_method_cache(VALUE klass) void rb_clear_cache(void) { - INC_VM_STATE_VERSION(); + rb_warning("rb_clear_cache() is deprecated."); + INC_METHOD_STATE_VERSION(); + INC_CONSTANT_STATE_VERSION(); } void -rb_clear_cache_by_class(VALUE klass) +rb_clear_constant_cache(void) +{ + INC_CONSTANT_STATE_VERSION(); +} + +void +rb_clear_method_cache_by_class(VALUE klass) { if (klass && klass != Qundef) { if (klass == rb_cBasicObject || klass == rb_cObject || klass == rb_mKernel) { - INC_VM_STATE_VERSION(); + INC_METHOD_STATE_VERSION(); } else { rb_class_clear_method_cache(klass); @@ -203,7 +211,7 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid) if (me) { make_method_entry_refined(me); - rb_clear_cache_by_class(refined_class); + rb_clear_method_cache_by_class(refined_class); } else { rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0, @@ -302,7 +310,7 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type, me = ALLOC(rb_method_entry_t); - rb_clear_cache_by_class(klass); + rb_clear_method_cache_by_class(klass); me->flag = NOEX_WITH_SAFE(noex); me->mark = 0; @@ -464,7 +472,7 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_ if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) { method_added(klass, mid); } - rb_clear_cache_by_class(klass); + rb_clear_method_cache_by_class(klass); return me; } @@ -542,7 +550,7 @@ rb_method_entry_get_without_cache(VALUE klass, ID id, struct cache_entry *ent; ent = GLOBAL_METHOD_CACHE(klass, id); ent->seq = RCLASS_EXT(klass)->seq; - ent->vm_state = GET_VM_STATE_VERSION(); + ent->method_state = GET_METHOD_STATE_VERSION(); ent->defined_class = defined_class; ent->mid = id; @@ -580,7 +588,7 @@ rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr) #if OPT_GLOBAL_METHOD_CACHE struct cache_entry *ent; ent = GLOBAL_METHOD_CACHE(klass, id); - if (ent->vm_state == GET_VM_STATE_VERSION() && + if (ent->method_state == GET_METHOD_STATE_VERSION() && ent->seq == RCLASS_EXT(klass)->seq && ent->mid == id) { if (defined_class_ptr) @@ -701,7 +709,7 @@ remove_method(VALUE klass, ID mid) st_delete(RCLASS_M_TBL(klass), &key, &data); rb_vm_check_redefinition_opt_method(me, klass); - rb_clear_cache_by_class(klass); + rb_clear_method_cache_by_class(klass); rb_unlink_method_entry(me); CALL_METHOD_HOOK(self, removed, mid); @@ -1232,7 +1240,7 @@ rb_alias(VALUE klass, ID name, ID def) if (flag == NOEX_UNDEF) flag = orig_me->flag; rb_method_entry_set(target_klass, name, orig_me, flag); - rb_clear_cache_by_class(target_klass); + rb_clear_method_cache_by_class(target_klass); } /* @@ -1287,7 +1295,7 @@ set_method_visibility(VALUE self, int argc, VALUE *argv, rb_method_flag_t ex) } rb_export_method(self, id, ex); } - rb_clear_cache_by_class(self); + rb_clear_method_cache_by_class(self); } static VALUE |