dont-invalidate-method-cache-when-defining-new-singleton-methods.patch

Charlie Somerville, 02/10/2013 02:13 AM

Download (4.55 KB)

View differences:

.gitignore
1
inst
1 2
*-*-*.def
2 3
*.a
3 4
*.bak
class.c
80 80
    RCLASS_SUPER(klass) = super;
81 81
    RCLASS_M_TBL(klass) = st_init_numtable();
82 82

  
83
    FL_SET(super, RCLASS_INHERITED_FLAG);
83 84
    OBJ_INFECT(klass, super);
84 85
    return (VALUE)klass;
85 86
}
include/ruby/ruby.h
748 748
#define RMODULE_IS_OVERLAID FL_USER2
749 749
#define RMODULE_IS_REFINEMENT FL_USER3
750 750
#define RMODULE_INCLUDED_INTO_REFINEMENT FL_USER4
751
#define RCLASS_INHERITED_FLAG FL_USER5
751 752

  
752 753
struct RFloat {
753 754
    struct RBasic basic;
insns.def
975 975
		  class_iseq->local_size, 0);
976 976
    RESTORE_REGS();
977 977

  
978
    INC_VM_STATE_VERSION();
979 978
    NEXT_INSN();
980 979
}
981 980

  
object.c
2756 2756

  
2757 2757
/*
2758 2758
 *  call-seq:
2759
 *     Class#has_subclass?  ->	bool
2760
 *
2761
 *  Returns true if the class has ever been subclassed.
2762
 *
2763
 *     Object.has_subclass?    #=> true
2764
 *     Class.new.has_subclass? #=> false
2765
 */
2766
VALUE
2767
rb_class_has_subclass_p(VALUE klass)
2768
{
2769
    return FL_TEST(klass, RCLASS_INHERITED_FLAG) ? Qtrue : Qfalse;
2770
}
2771

  
2772
/*
2773
 *  call-seq:
2759 2774
 *     Hash(arg)    -> hash
2760 2775
 *
2761 2776
 *  Converts <i>arg</i> to a <code>Hash</code> by calling
......
3105 3120

  
3106 3121
    rb_define_method(rb_cClass, "allocate", rb_obj_alloc, 0);
3107 3122
    rb_define_method(rb_cClass, "new", rb_class_new_instance, -1);
3123
    rb_define_method(rb_cClass, "has_subclass?", rb_class_has_subclass_p, 0);
3108 3124
    rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1);
3109 3125
    rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0);
3110 3126
    rb_define_alloc_func(rb_cClass, rb_class_s_alloc);
vm.c
2007 2007
    if (!is_singleton && noex == NOEX_MODFUNC) {
2008 2008
	rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
2009 2009
    }
2010
    INC_VM_STATE_VERSION();
2011 2010
}
2012 2011

  
2013 2012
#define REWIND_CFP(expr) do { \
......
2202 2201
static VALUE usage_analysis_register_stop(VALUE self);
2203 2202
#endif
2204 2203

  
2204
/*
2205
 *  call-seq:
2206
 *     RubyVM.state_version ->	int
2207
 *
2208
 *  Returns the current VM state version. The state version is used for
2209
 *  invalidating inline method and constant caches.
2210
 *
2211
 *  The state version is not guaranteed to be monotonic and may wrap around in
2212
 *  long running processes.
2213
 */
2214
static VALUE
2215
vm_state_version()
2216
{
2217
    return INT2FIX(ruby_vm_global_state_version);
2218
}
2219

  
2205 2220
void
2206 2221
Init_VM(void)
2207 2222
{
......
2213 2228
    rb_cRubyVM = rb_define_class("RubyVM", rb_cObject);
2214 2229
    rb_undef_alloc_func(rb_cRubyVM);
2215 2230
    rb_undef_method(CLASS_OF(rb_cRubyVM), "new");
2231
    rb_define_singleton_method(rb_cRubyVM, "state_version", vm_state_version, 0);
2216 2232

  
2217 2233
    /* FrozenCore (hidden) */
2218 2234
    fcore = rb_class_new(rb_cBasicObject);
vm_method.c
220 220
    }
221 221
}
222 222

  
223
static inline rb_method_entry_t*
224
search_method(VALUE klass, ID id, VALUE *defined_class_ptr);
225

  
223 226
static rb_method_entry_t *
224 227
rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
225 228
		     rb_method_definition_t *def, rb_method_flag_t noex)
......
315 318

  
316 319
    me = ALLOC(rb_method_entry_t);
317 320

  
318
    rb_clear_cache_by_id(mid);
321
    if (search_method(klass, mid, NULL) /* clear cache if overriding existing method */
322
	|| FL_TEST(klass, RCLASS_INHERITED_FLAG) /* or this class has subclasses */
323
	|| (RB_TYPE_P(klass, T_MODULE)) /* or this is a module */)
324
    {
325
        rb_clear_cache_by_id(mid);
326
    }
319 327

  
320 328
    me->flag = NOEX_WITH_SAFE(noex);
321 329
    me->mark = 0;
......
555 563

  
556 564
    ent = cache + EXPR1(klass, id);
557 565
    if (ent->filled_version == GET_VM_STATE_VERSION() &&
558
	ent->mid == id && ent->klass == klass) {
566
	ent->mid == id && ent->klass == klass && ent->me) {
559 567
	if (defined_class_ptr)
560 568
	    *defined_class_ptr = ent->defined_class;
561 569
	return ent->me;