mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* vm_method.c (rb_unlink_method_entry, rb_sweep_method_entry):
added. Unlinked method entries are collected to vm->unlinked_method_entry_list. On the GC timing, mark all method entries which are on all living threads. Only non-marked method entries are collected. This hack prevents releasing living method entry. [Performance Consideration] Since this Method Entry GC (MEGC) doesn't occuer frequently, MEGC will not be a performance bottleneck. However, to traverse living method entries, every control frame push needs to clear cfp->me field. This will be a performance issue (because pushing control frame is occurred frequently). Bug #2777 [ruby-dev:40457] * cont.c (fiber_init): init cfp->me. * gc.c (garbage_collect): kick rb_sweep_method_entry(). * method.h (rb_method_entry_t): add a mark field. * vm.c (invoke_block_from_c): set passed me. * vm.c (rb_thread_mark): mark cfp->me. * vm_core.h (rb_thread_t): add a field passed_me. * vm_core.h (rb_vm_t): add a field unlinked_method_entry_list. * vm_insnhelper.c (vm_push_frame): clear cfp->me at all times. * vm_insnhelper.c (vm_call_bmethod): pass me. * bootstraptest/test_method.rb: add a test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27634 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									34ed81ea89
								
							
						
					
					
						commit
						833cade2dc
					
				
					 10 changed files with 122 additions and 23 deletions
				
			
		
							
								
								
									
										35
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
					@ -1,3 +1,38 @@
 | 
				
			||||||
 | 
					Thu May  6 02:16:48 2010  Koichi Sasada  <ko1@atdot.net>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm_method.c (rb_unlink_method_entry, rb_sweep_method_entry):
 | 
				
			||||||
 | 
						  added.  Unlinked method entries are collected to
 | 
				
			||||||
 | 
						  vm->unlinked_method_entry_list.  On the GC timing, mark all method
 | 
				
			||||||
 | 
						  entries which are on all living threads.  Only non-marked method
 | 
				
			||||||
 | 
						  entries are collected.  This hack prevents releasing living method
 | 
				
			||||||
 | 
						  entry.
 | 
				
			||||||
 | 
						  [Performance Consideration] Since this Method Entry GC (MEGC)
 | 
				
			||||||
 | 
						  doesn't occuer frequently, MEGC will not be a performance bottleneck.
 | 
				
			||||||
 | 
						  However, to traverse living method entries, every control frame push
 | 
				
			||||||
 | 
						  needs to clear cfp->me field.  This will be a performance issue
 | 
				
			||||||
 | 
						  (because pushing control frame is occurred frequently).
 | 
				
			||||||
 | 
						  Bug #2777 [ruby-dev:40457]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* cont.c (fiber_init): init cfp->me.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* gc.c (garbage_collect): kick rb_sweep_method_entry().
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* method.h (rb_method_entry_t): add a mark field.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm.c (invoke_block_from_c): set passed me.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm.c (rb_thread_mark): mark cfp->me.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm_core.h (rb_thread_t): add a field passed_me.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm_core.h (rb_vm_t): add a field unlinked_method_entry_list.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm_insnhelper.c (vm_push_frame): clear cfp->me at all times.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* vm_insnhelper.c (vm_call_bmethod): pass me.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* bootstraptest/test_method.rb: add a test.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Wed May  5 22:22:51 2010  wanabe  <s.wanabe@gmail.com>
 | 
					Wed May  5 22:22:51 2010  wanabe  <s.wanabe@gmail.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	* compile.c (iseq_set_sequence): fix check range of ic_index.
 | 
						* compile.c (iseq_set_sequence): fix check range of ic_index.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1161,3 +1161,17 @@ assert_equal 'ok', %q{
 | 
				
			||||||
  "hello"[0, 1] ||= "H"
 | 
					  "hello"[0, 1] ||= "H"
 | 
				
			||||||
  "ok"
 | 
					  "ok"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					assert_equal 'ok', %q{
 | 
				
			||||||
 | 
					  class C
 | 
				
			||||||
 | 
					    define_method(:foo) do
 | 
				
			||||||
 | 
					      C.class_eval { remove_method(:foo) }
 | 
				
			||||||
 | 
					      super()
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  begin
 | 
				
			||||||
 | 
					    C.new.foo
 | 
				
			||||||
 | 
					  rescue NoMethodError
 | 
				
			||||||
 | 
					    'ok'
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								cont.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								cont.c
									
										
									
									
									
								
							| 
						 | 
					@ -771,6 +771,7 @@ fiber_init(VALUE fibval, VALUE proc)
 | 
				
			||||||
    th->cfp->iseq = 0;
 | 
					    th->cfp->iseq = 0;
 | 
				
			||||||
    th->cfp->proc = 0;
 | 
					    th->cfp->proc = 0;
 | 
				
			||||||
    th->cfp->block_iseq = 0;
 | 
					    th->cfp->block_iseq = 0;
 | 
				
			||||||
 | 
					    th->cfp->me = 0;
 | 
				
			||||||
    th->tag = 0;
 | 
					    th->tag = 0;
 | 
				
			||||||
    th->local_storage = st_init_numtable();
 | 
					    th->local_storage = st_init_numtable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								gc.c
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								gc.c
									
										
									
									
									
								
							| 
						 | 
					@ -2205,6 +2205,11 @@ garbage_collect(rb_objspace_t *objspace)
 | 
				
			||||||
    gc_sweep(objspace);
 | 
					    gc_sweep(objspace);
 | 
				
			||||||
    GC_PROF_SWEEP_TIMER_STOP;
 | 
					    GC_PROF_SWEEP_TIMER_STOP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* sweep unlinked method entries */
 | 
				
			||||||
 | 
					    if (th->vm->unlinked_method_entry_list) {
 | 
				
			||||||
 | 
						rb_sweep_method_entry(th->vm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GC_PROF_TIMER_STOP;
 | 
					    GC_PROF_TIMER_STOP;
 | 
				
			||||||
    if (GC_NOTIFY) printf("end garbage_collect()\n");
 | 
					    if (GC_NOTIFY) printf("end garbage_collect()\n");
 | 
				
			||||||
    return TRUE;
 | 
					    return TRUE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								method.h
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								method.h
									
										
									
									
									
								
							| 
						 | 
					@ -74,11 +74,17 @@ typedef struct rb_method_definition_struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct rb_method_entry_struct {
 | 
					typedef struct rb_method_entry_struct {
 | 
				
			||||||
    rb_method_flag_t flag;
 | 
					    rb_method_flag_t flag;
 | 
				
			||||||
 | 
					    char mark;
 | 
				
			||||||
    rb_method_definition_t *def;
 | 
					    rb_method_definition_t *def;
 | 
				
			||||||
    ID called_id;
 | 
					    ID called_id;
 | 
				
			||||||
    VALUE klass;                    /* should be mark */
 | 
					    VALUE klass;                    /* should be mark */
 | 
				
			||||||
} rb_method_entry_t;
 | 
					} rb_method_entry_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct unlinked_method_entry_list_entry {
 | 
				
			||||||
 | 
					    struct unlinked_method_entry_list_entry *next;
 | 
				
			||||||
 | 
					    rb_method_entry_t *me;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
 | 
					#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
 | 
					void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
 | 
				
			||||||
| 
						 | 
					@ -92,5 +98,6 @@ int rb_method_entry_arity(const rb_method_entry_t *me);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rb_mark_method_entry(const rb_method_entry_t *me);
 | 
					void rb_mark_method_entry(const rb_method_entry_t *me);
 | 
				
			||||||
void rb_free_method_entry(rb_method_entry_t *me);
 | 
					void rb_free_method_entry(rb_method_entry_t *me);
 | 
				
			||||||
 | 
					void rb_sweep_method_entry(void *vm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* METHOD_H */
 | 
					#endif /* METHOD_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
#define RUBY_VERSION "1.9.2"
 | 
					#define RUBY_VERSION "1.9.2"
 | 
				
			||||||
#define RUBY_RELEASE_DATE "2010-05-05"
 | 
					#define RUBY_RELEASE_DATE "2010-05-06"
 | 
				
			||||||
#define RUBY_PATCHLEVEL -1
 | 
					#define RUBY_PATCHLEVEL -1
 | 
				
			||||||
#define RUBY_BRANCH_NAME "trunk"
 | 
					#define RUBY_BRANCH_NAME "trunk"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
#define RUBY_VERSION_TEENY 1
 | 
					#define RUBY_VERSION_TEENY 1
 | 
				
			||||||
#define RUBY_RELEASE_YEAR 2010
 | 
					#define RUBY_RELEASE_YEAR 2010
 | 
				
			||||||
#define RUBY_RELEASE_MONTH 5
 | 
					#define RUBY_RELEASE_MONTH 5
 | 
				
			||||||
#define RUBY_RELEASE_DAY 5
 | 
					#define RUBY_RELEASE_DAY 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ruby/version.h"
 | 
					#include "ruby/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								vm.c
									
										
									
									
									
								
							| 
						 | 
					@ -528,6 +528,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
				
			||||||
    else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
 | 
					    else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
 | 
				
			||||||
	const rb_iseq_t *iseq = block->iseq;
 | 
						const rb_iseq_t *iseq = block->iseq;
 | 
				
			||||||
	const rb_control_frame_t *cfp;
 | 
						const rb_control_frame_t *cfp;
 | 
				
			||||||
 | 
						rb_control_frame_t *ncfp;
 | 
				
			||||||
	int i, opt_pc, arg_size = iseq->arg_size;
 | 
						int i, opt_pc, arg_size = iseq->arg_size;
 | 
				
			||||||
	int type = block_proc_is_lambda(block->proc) ?
 | 
						int type = block_proc_is_lambda(block->proc) ?
 | 
				
			||||||
	  VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
 | 
						  VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
 | 
				
			||||||
| 
						 | 
					@ -544,10 +545,12 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
				
			||||||
	opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr,
 | 
						opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr,
 | 
				
			||||||
				     type == VM_FRAME_MAGIC_LAMBDA);
 | 
									     type == VM_FRAME_MAGIC_LAMBDA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vm_push_frame(th, iseq, type,
 | 
						ncfp = vm_push_frame(th, iseq, type,
 | 
				
			||||||
		      self, GC_GUARDED_PTR(block->dfp),
 | 
								     self, GC_GUARDED_PTR(block->dfp),
 | 
				
			||||||
		      iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp,
 | 
								     iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp,
 | 
				
			||||||
		      iseq->local_size - arg_size);
 | 
								     iseq->local_size - arg_size);
 | 
				
			||||||
 | 
						ncfp->me = th->passed_me;
 | 
				
			||||||
 | 
						th->passed_me = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cref) {
 | 
						if (cref) {
 | 
				
			||||||
	    th->cfp->dfp[-1] = (VALUE)cref;
 | 
						    th->cfp->dfp[-1] = (VALUE)cref;
 | 
				
			||||||
| 
						 | 
					@ -1636,6 +1639,7 @@ rb_thread_mark(void *ptr)
 | 
				
			||||||
	    while (cfp != limit_cfp) {
 | 
						    while (cfp != limit_cfp) {
 | 
				
			||||||
		rb_gc_mark(cfp->proc);
 | 
							rb_gc_mark(cfp->proc);
 | 
				
			||||||
		if (cfp->iseq) rb_gc_mark(cfp->iseq->self);
 | 
							if (cfp->iseq) rb_gc_mark(cfp->iseq->self);
 | 
				
			||||||
 | 
							if (cfp->me) ((rb_method_entry_t *)cfp->me)->mark = 1;
 | 
				
			||||||
		cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
 | 
							cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,6 +307,8 @@ typedef struct rb_vm_struct {
 | 
				
			||||||
    VALUE verbose, debug, progname;
 | 
					    VALUE verbose, debug, progname;
 | 
				
			||||||
    VALUE coverages;
 | 
					    VALUE coverages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct unlinked_method_entry_list_entry *unlinked_method_entry_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
 | 
					#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
 | 
				
			||||||
    struct rb_objspace *objspace;
 | 
					    struct rb_objspace *objspace;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -387,6 +389,9 @@ typedef struct rb_thread_struct
 | 
				
			||||||
    /* for rb_iterate */
 | 
					    /* for rb_iterate */
 | 
				
			||||||
    const rb_block_t *passed_block;
 | 
					    const rb_block_t *passed_block;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* for bmethod */
 | 
				
			||||||
 | 
					    const rb_method_entry_t *passed_me;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* for load(true) */
 | 
					    /* for load(true) */
 | 
				
			||||||
    VALUE top_self;
 | 
					    VALUE top_self;
 | 
				
			||||||
    VALUE top_wrapper;
 | 
					    VALUE top_wrapper;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,7 @@ vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq,
 | 
				
			||||||
    cfp->lfp = lfp;
 | 
					    cfp->lfp = lfp;
 | 
				
			||||||
    cfp->dfp = sp;
 | 
					    cfp->dfp = sp;
 | 
				
			||||||
    cfp->proc = 0;
 | 
					    cfp->proc = 0;
 | 
				
			||||||
 | 
					    cfp->me = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define COLLECT_PROFILE 0
 | 
					#define COLLECT_PROFILE 0
 | 
				
			||||||
#if COLLECT_PROFILE
 | 
					#if COLLECT_PROFILE
 | 
				
			||||||
| 
						 | 
					@ -419,7 +420,7 @@ vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
 | 
				
			||||||
    VALUE val;
 | 
					    VALUE val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* control block frame */
 | 
					    /* control block frame */
 | 
				
			||||||
    (cfp-2)->me = me;
 | 
					    th->passed_me = me;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GetProcPtr(me->def->body.proc, proc);
 | 
					    GetProcPtr(me->def->body.proc, proc);
 | 
				
			||||||
    val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
 | 
					    val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										59
									
								
								vm_method.c
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								vm_method.c
									
										
									
									
									
								
							| 
						 | 
					@ -126,6 +126,44 @@ rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_me
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					rb_unlink_method_entry(rb_method_entry_t *me)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct unlinked_method_entry_list_entry *ume = ALLOC(struct unlinked_method_entry_list_entry);
 | 
				
			||||||
 | 
					    ume->me = me;
 | 
				
			||||||
 | 
					    ume->next = GET_VM()->unlinked_method_entry_list;
 | 
				
			||||||
 | 
					    GET_VM()->unlinked_method_entry_list = ume;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					rb_sweep_method_entry(void *pvm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    rb_vm_t *vm = pvm;
 | 
				
			||||||
 | 
					    struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list, *prev_ume = 0, *curr_ume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (ume) {
 | 
				
			||||||
 | 
						if (ume->me->mark) {
 | 
				
			||||||
 | 
						    ume->me->mark = 0;
 | 
				
			||||||
 | 
						    prev_ume = ume;
 | 
				
			||||||
 | 
						    ume = ume->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
						    rb_free_method_entry(ume->me);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    if (prev_ume == 0) {
 | 
				
			||||||
 | 
							vm->unlinked_method_entry_list = ume->next;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						    else {
 | 
				
			||||||
 | 
							prev_ume->next = ume->next;
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    curr_ume = ume;
 | 
				
			||||||
 | 
						    ume = ume->next;
 | 
				
			||||||
 | 
						    xfree(curr_ume);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
rb_free_method_entry(rb_method_entry_t *me)
 | 
					rb_free_method_entry(rb_method_entry_t *me)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -214,26 +252,15 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: this avoid to free methods used in cfp, but reusing may cause
 | 
						rb_unlink_method_entry(old_me);
 | 
				
			||||||
	 * another problem when the usage is changed.
 | 
					    }
 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	me = old_me;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (me->def) {
 | 
					    me = ALLOC(rb_method_entry_t);
 | 
				
			||||||
	    if (me->def->alias_count == 0)
 | 
					 | 
				
			||||||
		xfree(me->def);
 | 
					 | 
				
			||||||
	    else if (me->def->alias_count > 0)
 | 
					 | 
				
			||||||
		me->def->alias_count--;
 | 
					 | 
				
			||||||
	    me->def = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
	me = ALLOC(rb_method_entry_t);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rb_clear_cache_by_id(mid);
 | 
					    rb_clear_cache_by_id(mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    me->flag = NOEX_WITH_SAFE(noex);
 | 
					    me->flag = NOEX_WITH_SAFE(noex);
 | 
				
			||||||
 | 
					    me->mark = 0;
 | 
				
			||||||
    me->called_id = mid;
 | 
					    me->called_id = mid;
 | 
				
			||||||
    me->klass = klass;
 | 
					    me->klass = klass;
 | 
				
			||||||
    me->def = def;
 | 
					    me->def = def;
 | 
				
			||||||
| 
						 | 
					@ -453,7 +480,7 @@ remove_method(VALUE klass, ID mid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rb_vm_check_redefinition_opt_method(me);
 | 
					    rb_vm_check_redefinition_opt_method(me);
 | 
				
			||||||
    rb_clear_cache_for_undef(klass, mid);
 | 
					    rb_clear_cache_for_undef(klass, mid);
 | 
				
			||||||
    rb_free_method_entry(me);
 | 
					    rb_unlink_method_entry(me);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CALL_METHOD_HOOK(klass, removed, mid);
 | 
					    CALL_METHOD_HOOK(klass, removed, mid);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue