mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass. [Bug #11278], [Bug #11279] rb_method_entry_t data belong to modules/classes. rb_method_entry_t::owner points defined module or class. module M def foo; end end In this case, owner is M. rb_callable_method_entry_t data belong to only classes. For modules, MRI creates corresponding T_ICLASS internally. rb_callable_method_entry_t can also belong to T_ICLASS. rb_callable_method_entry_t::defined_class points T_CLASS or T_ICLASS. rb_method_entry_t data for classes (not for modules) are also rb_callable_method_entry_t data because it is completely same data. In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class. For example, there are classes C and D, and incldues M, class C; include M; end class D; include M; end then, two T_ICLASS objects for C's super class and D's super class will be created. When C.new.foo is called, then M#foo is searcheed and rb_callable_method_t data is used by VM to invoke M#foo. rb_method_entry_t data is only one for M#foo. However, rb_callable_method_entry_t data are two (and can be more). It is proportional to the number of including (and prepending) classes (the number of T_ICLASS which point to the module). Now, created rb_callable_method_entry_t are collected when the original module M was modified. We can think it is a cache. We need to select what kind of method entry data is needed. To operate definition, then you need to use rb_method_entry_t. You can access them by the following functions. * rb_method_entry(VALUE klass, ID id); * rb_method_entry_with_refinements(VALUE klass, ID id); * rb_method_entry_without_refinements(VALUE klass, ID id); * rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me); To invoke methods, then you need to use rb_callable_method_entry_t which you can get by the following APIs corresponding to the above listed functions. * rb_callable_method_entry(VALUE klass, ID id); * rb_callable_method_entry_with_refinements(VALUE klass, ID id); * rb_callable_method_entry_without_refinements(VALUE klass, ID id); * rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me); VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry() returns rb_callable_method_entry_t. You can check a super class of current method by rb_callable_method_entry_t::defined_class. * method.h: renamed from rb_method_entry_t::klass to rb_method_entry_t::owner. * internal.h: add rb_classext_struct::callable_m_tbl to cache rb_callable_method_entry_t data. We need to consider abotu this field again because it is only active for T_ICLASS. * class.c (method_entry_i): ditto. * class.c (rb_define_attr): rb_method_entry() does not takes defiend_class_ptr. * gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS. * cont.c (fiber_init): rb_control_frame_t::klass is removed. * proc.c: fix `struct METHOD' data structure because rb_callable_method_t has all information. * vm_core.h: remove several fields. * rb_control_frame_t::klass. * rb_block_t::klass. And catch up changes. * eval.c: catch up changes. * gc.c: ditto. * insns.def: ditto. * vm.c: ditto. * vm_args.c: ditto. * vm_backtrace.c: ditto. * vm_dump.c: ditto. * vm_eval.c: ditto. * vm_insnhelper.c: ditto. * vm_method.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									6ddfcd93fc
								
							
						
					
					
						commit
						5e8a147480
					
				
					 17 changed files with 753 additions and 458 deletions
				
			
		
							
								
								
									
										115
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										115
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,118 @@
 | 
			
		|||
Fri Jul 03 20:05:10 2015  Koichi Sasada  <ko1@atdot.net>
 | 
			
		||||
 | 
			
		||||
	* method.h: introduce rb_callable_method_entry_t to remove
 | 
			
		||||
	  rb_control_frame_t::klass.
 | 
			
		||||
	  [Bug #11278], [Bug #11279]
 | 
			
		||||
 | 
			
		||||
	  rb_method_entry_t data belong to modules/classes.
 | 
			
		||||
	  rb_method_entry_t::owner points defined module or class.
 | 
			
		||||
 | 
			
		||||
	    module M
 | 
			
		||||
	      def foo; end
 | 
			
		||||
	    end
 | 
			
		||||
 | 
			
		||||
	  In this case, owner is M.
 | 
			
		||||
 | 
			
		||||
	  rb_callable_method_entry_t data belong to only classes.
 | 
			
		||||
	  For modules, MRI creates corresponding T_ICLASS internally.
 | 
			
		||||
	  rb_callable_method_entry_t can also belong to T_ICLASS.
 | 
			
		||||
 | 
			
		||||
	  rb_callable_method_entry_t::defined_class points T_CLASS or
 | 
			
		||||
	  T_ICLASS.
 | 
			
		||||
	  rb_method_entry_t data for classes (not for modules) are also
 | 
			
		||||
	  rb_callable_method_entry_t data because it is completely same data.
 | 
			
		||||
	  In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
 | 
			
		||||
 | 
			
		||||
	  For example, there are classes C and D, and incldues M,
 | 
			
		||||
 | 
			
		||||
	    class C; include M; end
 | 
			
		||||
	    class D; include M; end
 | 
			
		||||
 | 
			
		||||
	  then, two T_ICLASS objects for C's super class and D's super class
 | 
			
		||||
	  will be created.
 | 
			
		||||
 | 
			
		||||
	  When C.new.foo is called, then M#foo is searcheed and
 | 
			
		||||
	  rb_callable_method_t data is used by VM to invoke M#foo.
 | 
			
		||||
 | 
			
		||||
	  rb_method_entry_t data is only one for M#foo.
 | 
			
		||||
	  However, rb_callable_method_entry_t data are two (and can be more).
 | 
			
		||||
	  It is proportional to the number of including (and prepending)
 | 
			
		||||
	  classes (the number of T_ICLASS which point to the module).
 | 
			
		||||
 | 
			
		||||
	  Now, created rb_callable_method_entry_t are collected when
 | 
			
		||||
	  the original module M was modified. We can think it is a cache.
 | 
			
		||||
 | 
			
		||||
	  We need to select what kind of method entry data is needed.
 | 
			
		||||
	  To operate definition, then you need to use rb_method_entry_t.
 | 
			
		||||
 | 
			
		||||
	  You can access them by the following functions.
 | 
			
		||||
 | 
			
		||||
	  * rb_method_entry(VALUE klass, ID id);
 | 
			
		||||
	  * rb_method_entry_with_refinements(VALUE klass, ID id);
 | 
			
		||||
	  * rb_method_entry_without_refinements(VALUE klass, ID id);
 | 
			
		||||
	  * rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
 | 
			
		||||
 | 
			
		||||
	  To invoke methods, then you need to use rb_callable_method_entry_t
 | 
			
		||||
	  which you can get by the following APIs corresponding to the
 | 
			
		||||
	  above listed functions.
 | 
			
		||||
 | 
			
		||||
	  * rb_callable_method_entry(VALUE klass, ID id);
 | 
			
		||||
	  * rb_callable_method_entry_with_refinements(VALUE klass, ID id);
 | 
			
		||||
	  * rb_callable_method_entry_without_refinements(VALUE klass, ID id);
 | 
			
		||||
	  * rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
 | 
			
		||||
 | 
			
		||||
	  VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
 | 
			
		||||
	  returns rb_callable_method_entry_t.
 | 
			
		||||
	  You can check a super class of current method by
 | 
			
		||||
	  rb_callable_method_entry_t::defined_class.
 | 
			
		||||
 | 
			
		||||
	* method.h: renamed from rb_method_entry_t::klass to
 | 
			
		||||
	  rb_method_entry_t::owner.
 | 
			
		||||
 | 
			
		||||
	* internal.h: add rb_classext_struct::callable_m_tbl to cache
 | 
			
		||||
	  rb_callable_method_entry_t data.
 | 
			
		||||
 | 
			
		||||
	  We need to consider abotu this field again because it is only
 | 
			
		||||
	  active for T_ICLASS.
 | 
			
		||||
 | 
			
		||||
	* class.c (method_entry_i): ditto.
 | 
			
		||||
 | 
			
		||||
	* class.c (rb_define_attr): rb_method_entry() does not takes
 | 
			
		||||
	  defiend_class_ptr.
 | 
			
		||||
 | 
			
		||||
	* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
 | 
			
		||||
 | 
			
		||||
	* cont.c (fiber_init): rb_control_frame_t::klass is removed.
 | 
			
		||||
 | 
			
		||||
	* proc.c: fix `struct METHOD' data structure because
 | 
			
		||||
	  rb_callable_method_t has all information.
 | 
			
		||||
 | 
			
		||||
	* vm_core.h: remove several fields.
 | 
			
		||||
	  * rb_control_frame_t::klass.
 | 
			
		||||
	  * rb_block_t::klass.
 | 
			
		||||
 | 
			
		||||
	  And catch up changes.
 | 
			
		||||
 | 
			
		||||
	* eval.c: catch up changes.
 | 
			
		||||
 | 
			
		||||
	* gc.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* insns.def: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm_args.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm_backtrace.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm_dump.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm_eval.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm_insnhelper.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm_method.c: ditto.
 | 
			
		||||
 | 
			
		||||
Fri Jul  3 14:30:18 2015  Nobuyoshi Nakada  <nobu@ruby-lang.org>
 | 
			
		||||
 | 
			
		||||
	* win32/file.c: some mingw compilers need a tweek for the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								class.c
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								class.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1119,10 +1119,10 @@ method_entry_i(st_data_t key, st_data_t value, st_data_t data)
 | 
			
		|||
    rb_method_visibility_t type;
 | 
			
		||||
 | 
			
		||||
    if (me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	VALUE klass = me->klass;
 | 
			
		||||
	me = rb_resolve_refined_method(Qnil, me, NULL);
 | 
			
		||||
	VALUE owner = me->owner;
 | 
			
		||||
	me = rb_resolve_refined_method(Qnil, me);
 | 
			
		||||
	if (!me) return ST_CONTINUE;
 | 
			
		||||
	if (!arg->recur && me->klass != klass) return ST_CONTINUE;
 | 
			
		||||
	if (!arg->recur && me->owner != owner) return ST_CONTINUE;
 | 
			
		||||
    }
 | 
			
		||||
    if (!st_lookup(arg->list, key, 0)) {
 | 
			
		||||
	if (UNDEFINED_METHOD_ENTRY_P(me)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1718,7 +1718,7 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
 | 
			
		|||
int
 | 
			
		||||
rb_obj_basic_to_s_p(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"), 0);
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"));
 | 
			
		||||
    if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
 | 
			
		||||
	me->def->body.cfunc.func == rb_any_to_s)
 | 
			
		||||
	return 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								cont.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								cont.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1203,7 +1203,6 @@ fiber_init(VALUE fibval, VALUE proc)
 | 
			
		|||
    th->cfp->ep = th->stack;
 | 
			
		||||
    *th->cfp->ep = VM_ENVVAL_BLOCK_PTR(0);
 | 
			
		||||
    th->cfp->self = Qnil;
 | 
			
		||||
    th->cfp->klass = Qnil;
 | 
			
		||||
    th->cfp->flag = 0;
 | 
			
		||||
    th->cfp->iseq = 0;
 | 
			
		||||
    th->cfp->proc = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								eval.c
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								eval.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -748,8 +748,8 @@ rb_raise_jump(VALUE mesg, VALUE cause)
 | 
			
		|||
{
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
    const rb_control_frame_t *cfp = th->cfp;
 | 
			
		||||
    const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
    VALUE klass = me->klass;
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
    VALUE klass = me->owner;
 | 
			
		||||
    VALUE self = cfp->self;
 | 
			
		||||
    ID mid = me->called_id;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -922,7 +922,7 @@ rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE
 | 
			
		|||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const rb_method_entry_t *
 | 
			
		||||
static const rb_callable_method_entry_t *
 | 
			
		||||
method_entry_of_iseq(const rb_control_frame_t *cfp, const rb_iseq_t *iseq)
 | 
			
		||||
{
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
| 
						 | 
				
			
			@ -939,9 +939,9 @@ method_entry_of_iseq(const rb_control_frame_t *cfp, const rb_iseq_t *iseq)
 | 
			
		|||
static ID
 | 
			
		||||
frame_func_id(rb_control_frame_t *cfp)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me_local;
 | 
			
		||||
    const rb_iseq_t *iseq = cfp->iseq;
 | 
			
		||||
    const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
    const rb_callable_method_entry_t *me_local;
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
 | 
			
		||||
    if (me) {
 | 
			
		||||
	return me->def->original_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -970,9 +970,9 @@ frame_func_id(rb_control_frame_t *cfp)
 | 
			
		|||
static ID
 | 
			
		||||
frame_called_id(rb_control_frame_t *cfp)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me_local;
 | 
			
		||||
    const rb_iseq_t *iseq = cfp->iseq;
 | 
			
		||||
    const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
    const rb_callable_method_entry_t *me_local;
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
 | 
			
		||||
    if (me) {
 | 
			
		||||
	return me->called_id;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								gc.c
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								gc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2105,6 +2105,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
 | 
			
		|||
	if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
 | 
			
		||||
	    rb_free_m_tbl(RCLASS_M_TBL(obj));
 | 
			
		||||
	}
 | 
			
		||||
	rb_free_m_tbl(RCLASS_CALLABLE_M_TBL(obj));
 | 
			
		||||
	if (RCLASS_EXT(obj)->subclasses) {
 | 
			
		||||
	    rb_class_detach_subclasses(obj);
 | 
			
		||||
	    RCLASS_EXT(obj)->subclasses = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -3926,7 +3927,8 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
 | 
			
		|||
{
 | 
			
		||||
    const rb_method_definition_t *def = me->def;
 | 
			
		||||
 | 
			
		||||
    gc_mark(objspace, me->klass);
 | 
			
		||||
    gc_mark(objspace, me->owner);
 | 
			
		||||
    gc_mark(objspace, me->defined_class);
 | 
			
		||||
 | 
			
		||||
    if (def) {
 | 
			
		||||
	switch (def->type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3946,6 +3948,7 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
 | 
			
		|||
	    return;
 | 
			
		||||
	  case VM_METHOD_TYPE_REFINED:
 | 
			
		||||
	    gc_mark(objspace, (VALUE)def->body.refined.orig_me);
 | 
			
		||||
	    gc_mark(objspace, (VALUE)def->body.refined.owner);
 | 
			
		||||
	    break;
 | 
			
		||||
	  case VM_METHOD_TYPE_CFUNC:
 | 
			
		||||
	  case VM_METHOD_TYPE_ZSUPER:
 | 
			
		||||
| 
						 | 
				
			
			@ -4324,6 +4327,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
 | 
			
		|||
	if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
 | 
			
		||||
	    mark_m_tbl(objspace, RCLASS_M_TBL(obj));
 | 
			
		||||
	}
 | 
			
		||||
	mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
 | 
			
		||||
	if (!RCLASS_EXT(obj)) break;
 | 
			
		||||
	gc_mark(objspace, RCLASS_SUPER((VALUE)obj));
 | 
			
		||||
	break;
 | 
			
		||||
| 
						 | 
				
			
			@ -8953,7 +8957,7 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
 | 
			
		|||
	  if (imemo_type(obj) == imemo_ment) {
 | 
			
		||||
	      const rb_method_entry_t *me = &RANY(obj)->as.imemo.ment;
 | 
			
		||||
	      snprintf(buff, buff_size, "%s (called_id: %s, type: %s, alias: %d, class: %s)", buff,
 | 
			
		||||
		       rb_id2name(me->called_id), method_type_name(me->def->type), me->def->alias_count, obj_info(me->klass));
 | 
			
		||||
		       rb_id2name(me->called_id), method_type_name(me->def->type), me->def->alias_count, obj_info(me->defined_class));
 | 
			
		||||
	  }
 | 
			
		||||
      }
 | 
			
		||||
      default:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -914,8 +914,7 @@ defineclass
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /* enter scope */
 | 
			
		||||
    vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS,
 | 
			
		||||
		  klass, 0,
 | 
			
		||||
    vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, klass,
 | 
			
		||||
		  VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
 | 
			
		||||
		  (VALUE)vm_cref_push(th, klass, NULL),
 | 
			
		||||
		  class_iseq->iseq_encoded, GET_SP(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -456,6 +456,7 @@ struct rb_classext_struct {
 | 
			
		|||
    struct st_table *iv_index_tbl;
 | 
			
		||||
    struct st_table *iv_tbl;
 | 
			
		||||
    struct st_table *const_tbl;
 | 
			
		||||
    struct st_table *callable_m_tbl;
 | 
			
		||||
    rb_subclass_entry_t *subclasses;
 | 
			
		||||
    rb_subclass_entry_t **parent_subclasses;
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -477,6 +478,7 @@ void rb_class_remove_from_super_subclasses(VALUE);
 | 
			
		|||
#define RCLASS_IV_TBL(c) (RCLASS_EXT(c)->iv_tbl)
 | 
			
		||||
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
 | 
			
		||||
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
 | 
			
		||||
#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
 | 
			
		||||
#define RCLASS_IV_INDEX_TBL(c) (RCLASS_EXT(c)->iv_index_tbl)
 | 
			
		||||
#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_)
 | 
			
		||||
#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								method.h
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								method.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -47,12 +47,20 @@ typedef struct rb_cref_struct {
 | 
			
		|||
 | 
			
		||||
typedef struct rb_method_entry_struct {
 | 
			
		||||
    VALUE flags;
 | 
			
		||||
    VALUE dummy;
 | 
			
		||||
    const VALUE defined_class;
 | 
			
		||||
    struct rb_method_definition_struct * const def;
 | 
			
		||||
    ID called_id;
 | 
			
		||||
    const VALUE klass;    /* should be marked */
 | 
			
		||||
    const VALUE owner;
 | 
			
		||||
} rb_method_entry_t;
 | 
			
		||||
 | 
			
		||||
typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */
 | 
			
		||||
    VALUE flags;
 | 
			
		||||
    const VALUE defined_class;
 | 
			
		||||
    struct rb_method_definition_struct * const def;
 | 
			
		||||
    ID called_id;
 | 
			
		||||
    const VALUE owner;
 | 
			
		||||
} rb_callable_method_entry_t;
 | 
			
		||||
 | 
			
		||||
#define METHOD_ENTRY_VISI(me)  (rb_method_visibility_t)(((me)->flags & (IMEMO_FL_USER0 | IMEMO_FL_USER1)) >> (IMEMO_FL_USHIFT+0))
 | 
			
		||||
#define METHOD_ENTRY_BASIC(me) (int)                   (((me)->flags & (IMEMO_FL_USER2                 )) >> (IMEMO_FL_USHIFT+2))
 | 
			
		||||
#define METHOD_ENTRY_SAFE(me)  (int)                   (((me)->flags & (IMEMO_FL_USER3 | IMEMO_FL_USER4)) >> (IMEMO_FL_USHIFT+3))
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +93,13 @@ METHOD_ENTRY_FLAGS_SET(rb_method_entry_t *me, rb_method_visibility_t visi, unsig
 | 
			
		|||
      (me->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4)) |
 | 
			
		||||
	((visi << IMEMO_FL_USHIFT+0) | (basic << (IMEMO_FL_USHIFT+2)) | (safe << IMEMO_FL_USHIFT+3));
 | 
			
		||||
}
 | 
			
		||||
static inline void
 | 
			
		||||
METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
 | 
			
		||||
{
 | 
			
		||||
    dst->flags =
 | 
			
		||||
      (dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4)) |
 | 
			
		||||
	(src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VM_METHOD_TYPE_ISEQ,
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +142,7 @@ typedef struct rb_method_alias_struct {
 | 
			
		|||
 | 
			
		||||
typedef struct rb_method_refined_struct {
 | 
			
		||||
    const struct rb_method_entry_struct * const orig_me;
 | 
			
		||||
    const VALUE owner;
 | 
			
		||||
} rb_method_refined_t;
 | 
			
		||||
 | 
			
		||||
typedef struct rb_method_definition_struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -159,20 +175,23 @@ typedef struct rb_method_definition_struct {
 | 
			
		|||
 | 
			
		||||
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi);
 | 
			
		||||
void rb_add_method_iseq(VALUE klass, ID mid, VALUE iseqval, rb_cref_t *cref, rb_method_visibility_t visi);
 | 
			
		||||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
 | 
			
		||||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
 | 
			
		||||
rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
 | 
			
		||||
void rb_add_refined_method_entry(VALUE refined_class, ID mid);
 | 
			
		||||
const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements,
 | 
			
		||||
						   const rb_method_entry_t *me,
 | 
			
		||||
						   VALUE *defined_class_ptr);
 | 
			
		||||
const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id,
 | 
			
		||||
							  VALUE *defined_class_ptr);
 | 
			
		||||
const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id,
 | 
			
		||||
							     VALUE *defined_class_ptr);
 | 
			
		||||
 | 
			
		||||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
 | 
			
		||||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
 | 
			
		||||
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex);
 | 
			
		||||
rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
 | 
			
		||||
const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id);
 | 
			
		||||
const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id);
 | 
			
		||||
const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
 | 
			
		||||
 | 
			
		||||
const rb_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id);
 | 
			
		||||
const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id);
 | 
			
		||||
const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id);
 | 
			
		||||
const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
 | 
			
		||||
 | 
			
		||||
int rb_method_entry_arity(const rb_method_entry_t *me);
 | 
			
		||||
int rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2);
 | 
			
		||||
| 
						 | 
				
			
			@ -185,8 +204,8 @@ VALUE rb_obj_method_location(VALUE obj, ID id);
 | 
			
		|||
void rb_free_method_entry(const rb_method_entry_t *me);
 | 
			
		||||
void rb_sweep_method_entry(void *vm);
 | 
			
		||||
 | 
			
		||||
rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
 | 
			
		||||
rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
 | 
			
		||||
const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
 | 
			
		||||
const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, VALUE defined_class);
 | 
			
		||||
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
 | 
			
		||||
 | 
			
		||||
void rb_scope_visibility_set(rb_method_visibility_t);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										203
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										203
									
								
								proc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -21,11 +21,10 @@
 | 
			
		|||
const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
 | 
			
		||||
 | 
			
		||||
struct METHOD {
 | 
			
		||||
    VALUE recv;
 | 
			
		||||
    VALUE rclass;
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    ID id;
 | 
			
		||||
    rb_method_entry_t * const me;
 | 
			
		||||
    const VALUE recv;
 | 
			
		||||
    const VALUE klass;
 | 
			
		||||
    const rb_method_entry_t * const me;
 | 
			
		||||
    /* for bound methods, `me' should be rb_callable_method_entry_t * */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
VALUE rb_cUnboundMethod;
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,9 +1104,8 @@ static void
 | 
			
		|||
bm_mark(void *ptr)
 | 
			
		||||
{
 | 
			
		||||
    struct METHOD *data = ptr;
 | 
			
		||||
    rb_gc_mark(data->defined_class);
 | 
			
		||||
    rb_gc_mark(data->rclass);
 | 
			
		||||
    rb_gc_mark(data->recv);
 | 
			
		||||
    rb_gc_mark(data->klass);
 | 
			
		||||
    rb_gc_mark((VALUE)data->me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,17 +1155,15 @@ respond_to_missing_p(VALUE klass, VALUE obj, VALUE sym, int scope)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass)
 | 
			
		||||
mnew_missing(VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass)
 | 
			
		||||
{
 | 
			
		||||
    struct METHOD *data;
 | 
			
		||||
    VALUE method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
 | 
			
		||||
    rb_method_entry_t *me;
 | 
			
		||||
    rb_method_definition_t *def;
 | 
			
		||||
 | 
			
		||||
    data->recv = obj;
 | 
			
		||||
    data->rclass = rclass;
 | 
			
		||||
    data->defined_class = klass;
 | 
			
		||||
    data->id = rid;
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->recv, obj);
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->klass, klass);
 | 
			
		||||
 | 
			
		||||
    def = ZALLOC(rb_method_definition_t);
 | 
			
		||||
    def->type = VM_METHOD_TYPE_MISSING;
 | 
			
		||||
| 
						 | 
				
			
			@ -1183,11 +1179,10 @@ mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
 | 
			
		||||
mnew_internal(const rb_method_entry_t *me, VALUE klass,
 | 
			
		||||
	      VALUE obj, ID id, VALUE mclass, int scope, int error)
 | 
			
		||||
{
 | 
			
		||||
    struct METHOD *data;
 | 
			
		||||
    VALUE rclass = klass;
 | 
			
		||||
    VALUE method;
 | 
			
		||||
    ID rid = id;
 | 
			
		||||
    rb_method_visibility_t visi = METHOD_VISI_UNDEF;
 | 
			
		||||
| 
						 | 
				
			
			@ -1195,7 +1190,7 @@ mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
 | 
			
		|||
  again:
 | 
			
		||||
    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 | 
			
		||||
	if (respond_to_missing_p(klass, obj, ID2SYM(id), scope)) {
 | 
			
		||||
	    return mnew_missing(rclass, klass, obj, id, rid, mclass);
 | 
			
		||||
	    return mnew_missing(klass, obj, id, rid, mclass);
 | 
			
		||||
	}
 | 
			
		||||
	if (!error) return Qnil;
 | 
			
		||||
	rb_print_undef(klass, id, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -1208,44 +1203,52 @@ mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
 | 
			
		|||
	}
 | 
			
		||||
    }
 | 
			
		||||
    if (me->def->type == VM_METHOD_TYPE_ZSUPER) {
 | 
			
		||||
	klass = RCLASS_SUPER(defined_class);
 | 
			
		||||
	id = me->def->original_id;
 | 
			
		||||
	me = rb_method_entry_without_refinements(klass, id, &defined_class);
 | 
			
		||||
	if (me->defined_class) {
 | 
			
		||||
	    VALUE klass = RCLASS_SUPER(me->defined_class);
 | 
			
		||||
	    id = me->def->original_id;
 | 
			
		||||
	    me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    VALUE klass = RCLASS_SUPER(me->owner);
 | 
			
		||||
	    id = me->def->original_id;
 | 
			
		||||
	    me = rb_method_entry_without_refinements(klass, id);
 | 
			
		||||
	}
 | 
			
		||||
	goto again;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    klass = defined_class;
 | 
			
		||||
 | 
			
		||||
    while (rclass != klass &&
 | 
			
		||||
	   (FL_TEST(rclass, FL_SINGLETON) || RB_TYPE_P(rclass, T_ICLASS))) {
 | 
			
		||||
	rclass = RCLASS_SUPER(rclass);
 | 
			
		||||
    while (klass != me->owner && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
 | 
			
		||||
	klass = RCLASS_SUPER(klass);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
 | 
			
		||||
 | 
			
		||||
    data->recv = obj;
 | 
			
		||||
    data->rclass = rclass;
 | 
			
		||||
    data->defined_class = defined_class;
 | 
			
		||||
    data->id = rid;
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(me));
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->recv, obj);
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->klass, klass);
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->me, me);
 | 
			
		||||
 | 
			
		||||
    OBJ_INFECT(method, klass);
 | 
			
		||||
    return method;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
mnew_from_me(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
 | 
			
		||||
mnew_from_me(const rb_method_entry_t *me, VALUE klass,
 | 
			
		||||
	     VALUE obj, ID id, VALUE mclass, int scope)
 | 
			
		||||
{
 | 
			
		||||
    return mnew_internal(me, defined_class, klass, obj, id, mclass, scope, TRUE);
 | 
			
		||||
    return mnew_internal(me, klass, obj, id, mclass, scope, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    const rb_method_entry_t *me =
 | 
			
		||||
	rb_method_entry_without_refinements(klass, id, &defined_class);
 | 
			
		||||
    return mnew_from_me(me, defined_class, klass, obj, id, mclass, scope);
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    if (obj == Qundef) { /* UnboundMethod */
 | 
			
		||||
	me = rb_method_entry_without_refinements(klass, id);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id);
 | 
			
		||||
    }
 | 
			
		||||
    return mnew_from_me(me, klass, obj, id, mclass, scope);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1287,6 +1290,7 @@ static VALUE
 | 
			
		|||
method_eq(VALUE method, VALUE other)
 | 
			
		||||
{
 | 
			
		||||
    struct METHOD *m1, *m2;
 | 
			
		||||
    VALUE klass1, klass2;
 | 
			
		||||
 | 
			
		||||
    if (!rb_obj_is_method(other))
 | 
			
		||||
	return Qfalse;
 | 
			
		||||
| 
						 | 
				
			
			@ -1297,8 +1301,12 @@ method_eq(VALUE method, VALUE other)
 | 
			
		|||
    m1 = (struct METHOD *)DATA_PTR(method);
 | 
			
		||||
    m2 = (struct METHOD *)DATA_PTR(other);
 | 
			
		||||
 | 
			
		||||
    klass1 = m1->me->defined_class ? m1->me->defined_class : m1->me->owner;
 | 
			
		||||
    klass2 = m2->me->defined_class ? m2->me->defined_class : m2->me->owner;
 | 
			
		||||
 | 
			
		||||
    if (!rb_method_entry_eq(m1->me, m2->me) ||
 | 
			
		||||
	m1->rclass != m2->rclass ||
 | 
			
		||||
	klass1 != klass2 ||
 | 
			
		||||
	m1->klass != m2->klass ||
 | 
			
		||||
	m1->recv != m2->recv) {
 | 
			
		||||
	return Qfalse;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1322,8 +1330,7 @@ method_hash(VALUE method)
 | 
			
		|||
    st_index_t hash;
 | 
			
		||||
 | 
			
		||||
    TypedData_Get_Struct(method, struct METHOD, &method_data_type, m);
 | 
			
		||||
    hash = rb_hash_start((st_index_t)m->rclass);
 | 
			
		||||
    hash = rb_hash_uint(hash, (st_index_t)m->recv);
 | 
			
		||||
    hash = rb_hash_start((st_index_t)m->recv);
 | 
			
		||||
    hash = rb_hash_method_entry(hash, m->me);
 | 
			
		||||
    hash = rb_hash_end(hash);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1348,11 +1355,9 @@ method_unbind(VALUE obj)
 | 
			
		|||
    TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig);
 | 
			
		||||
    method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD,
 | 
			
		||||
				   &method_data_type, data);
 | 
			
		||||
    data->recv = Qundef;
 | 
			
		||||
    data->id = orig->id;
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->recv, Qundef);
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->klass, orig->klass);
 | 
			
		||||
    RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
 | 
			
		||||
    data->rclass = orig->rclass;
 | 
			
		||||
    data->defined_class = orig->defined_class;
 | 
			
		||||
    OBJ_INFECT(method, obj);
 | 
			
		||||
 | 
			
		||||
    return method;
 | 
			
		||||
| 
						 | 
				
			
			@ -1387,7 +1392,7 @@ method_name(VALUE obj)
 | 
			
		|||
    struct METHOD *data;
 | 
			
		||||
 | 
			
		||||
    TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
 | 
			
		||||
    return ID2SYM(data->id);
 | 
			
		||||
    return ID2SYM(data->me->called_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1417,16 +1422,8 @@ static VALUE
 | 
			
		|||
method_owner(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
    struct METHOD *data;
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
 | 
			
		||||
    TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
 | 
			
		||||
    defined_class = data->defined_class;
 | 
			
		||||
 | 
			
		||||
    if (RB_TYPE_P(defined_class, T_ICLASS)) {
 | 
			
		||||
	defined_class = RBASIC_CLASS(defined_class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return defined_class;
 | 
			
		||||
    return data->me->owner;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			@ -1462,7 +1459,7 @@ obj_method(VALUE obj, VALUE vid, int scope)
 | 
			
		|||
    if (!id) {
 | 
			
		||||
	if (respond_to_missing_p(klass, obj, vid, scope)) {
 | 
			
		||||
	    id = rb_intern_str(vid);
 | 
			
		||||
	    return mnew_missing(klass, klass, obj, id, id, mclass);
 | 
			
		||||
	    return mnew_missing(klass, obj, id, id, mclass);
 | 
			
		||||
	}
 | 
			
		||||
	rb_method_name_error(klass, vid);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1551,7 +1548,7 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
 | 
			
		|||
	if (!NIL_P(klass = rb_singleton_class_get(obj)) &&
 | 
			
		||||
	    respond_to_missing_p(klass, obj, vid, FALSE)) {
 | 
			
		||||
	    id = rb_intern_str(vid);
 | 
			
		||||
	    return mnew_missing(klass, klass, obj, id, id, rb_cMethod);
 | 
			
		||||
	    return mnew_missing(klass, obj, id, id, rb_cMethod);
 | 
			
		||||
	}
 | 
			
		||||
	rb_name_error_str(vid, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'",
 | 
			
		||||
			  QUOTE(vid), obj);
 | 
			
		||||
| 
						 | 
				
			
			@ -1562,7 +1559,7 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
 | 
			
		|||
	rb_name_error(id, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'",
 | 
			
		||||
		      QUOTE_ID(id), obj);
 | 
			
		||||
    }
 | 
			
		||||
    return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE);
 | 
			
		||||
    return mnew_from_me(me, klass, obj, id, rb_cMethod, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1704,17 +1701,16 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
 | 
			
		|||
 | 
			
		||||
    if (is_method) {
 | 
			
		||||
	struct METHOD *method = (struct METHOD *)DATA_PTR(body);
 | 
			
		||||
	VALUE rclass = method->rclass;
 | 
			
		||||
	if (rclass != mod && !RB_TYPE_P(rclass, T_MODULE) &&
 | 
			
		||||
	    !RTEST(rb_class_inherited_p(mod, rclass))) {
 | 
			
		||||
	    if (FL_TEST(rclass, FL_SINGLETON)) {
 | 
			
		||||
	if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) &&
 | 
			
		||||
	    !RTEST(rb_class_inherited_p(mod, method->me->owner))) {
 | 
			
		||||
	    if (FL_TEST(method->me->owner, FL_SINGLETON)) {
 | 
			
		||||
		rb_raise(rb_eTypeError,
 | 
			
		||||
			 "can't bind singleton method to a different class");
 | 
			
		||||
	    }
 | 
			
		||||
	    else {
 | 
			
		||||
		rb_raise(rb_eTypeError,
 | 
			
		||||
			 "bind argument must be a subclass of % "PRIsVALUE,
 | 
			
		||||
			 rb_class_name(rclass));
 | 
			
		||||
			 rb_class_name(method->me->owner));
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	rb_method_entry_set(mod, id, method->me, scope_visi->method_visi);
 | 
			
		||||
| 
						 | 
				
			
			@ -1732,7 +1728,6 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
 | 
			
		|||
	    RB_OBJ_WRITE(proc->block.iseq->self, &proc->block.iseq->klass, mod);
 | 
			
		||||
	    proc->is_lambda = TRUE;
 | 
			
		||||
	    proc->is_from_method = TRUE;
 | 
			
		||||
	    proc->block.klass = mod;
 | 
			
		||||
	}
 | 
			
		||||
	rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, scope_visi->method_visi);
 | 
			
		||||
	if (scope_visi->module_func) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1826,10 +1821,8 @@ method_clone(VALUE self)
 | 
			
		|||
    TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
 | 
			
		||||
    clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
 | 
			
		||||
    CLONESETUP(clone, self);
 | 
			
		||||
    data->recv = orig->recv;
 | 
			
		||||
    data->rclass = orig->rclass;
 | 
			
		||||
    data->defined_class = orig->defined_class;
 | 
			
		||||
    data->id = orig->id;
 | 
			
		||||
    RB_OBJ_WRITE(clone, &data->recv, orig->recv);
 | 
			
		||||
    RB_OBJ_WRITE(clone, &data->klass, orig->klass);
 | 
			
		||||
    RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
 | 
			
		||||
    return clone;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1854,6 +1847,13 @@ rb_method_call(int argc, const VALUE *argv, VALUE method)
 | 
			
		|||
    return rb_method_call_with_block(argc, argv, method, proc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const rb_callable_method_entry_t *
 | 
			
		||||
method_callable_method_entry(struct METHOD *data)
 | 
			
		||||
{
 | 
			
		||||
    if (data->me && data->me->defined_class == 0) rb_bug("method_callable_method_entry: not callable.");
 | 
			
		||||
    return (const rb_callable_method_entry_t *)data->me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_procval)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1877,7 +1877,6 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_
 | 
			
		|||
    if ((state = EXEC_TAG()) == 0) {
 | 
			
		||||
	rb_thread_t *th = GET_THREAD();
 | 
			
		||||
	rb_block_t *block = 0;
 | 
			
		||||
	VALUE defined_class;
 | 
			
		||||
 | 
			
		||||
	if (!NIL_P(pass_procval)) {
 | 
			
		||||
	    rb_proc_t *pass_proc;
 | 
			
		||||
| 
						 | 
				
			
			@ -1887,9 +1886,7 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_
 | 
			
		|||
 | 
			
		||||
	th->passed_block = block;
 | 
			
		||||
	VAR_INITIALIZED(data);
 | 
			
		||||
	defined_class = data->defined_class;
 | 
			
		||||
	if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass;
 | 
			
		||||
	result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, defined_class);
 | 
			
		||||
	result = rb_vm_call(th, data->recv, data->me->called_id, argc, argv, method_callable_method_entry(data));
 | 
			
		||||
    }
 | 
			
		||||
    POP_TAG();
 | 
			
		||||
    if (safe >= 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1994,12 +1991,12 @@ static VALUE
 | 
			
		|||
umethod_bind(VALUE method, VALUE recv)
 | 
			
		||||
{
 | 
			
		||||
    struct METHOD *data, *bound;
 | 
			
		||||
    VALUE methclass;
 | 
			
		||||
    VALUE rclass;
 | 
			
		||||
    VALUE methclass, klass;
 | 
			
		||||
 | 
			
		||||
    TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
 | 
			
		||||
 | 
			
		||||
    methclass = data->rclass;
 | 
			
		||||
    methclass = data->me->owner;
 | 
			
		||||
 | 
			
		||||
    if (!RB_TYPE_P(methclass, T_MODULE) &&
 | 
			
		||||
	methclass != CLASS_OF(recv) && !rb_obj_is_kind_of(recv, methclass)) {
 | 
			
		||||
	if (FL_TEST(methclass, FL_SINGLETON)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2012,24 +2009,23 @@ umethod_bind(VALUE method, VALUE recv)
 | 
			
		|||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    klass  = CLASS_OF(recv);
 | 
			
		||||
 | 
			
		||||
    method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
 | 
			
		||||
    bound->recv = data->recv;
 | 
			
		||||
    bound->rclass = data->rclass;
 | 
			
		||||
    bound->defined_class = data->defined_class;
 | 
			
		||||
    bound->id = data->id;
 | 
			
		||||
    RB_OBJ_WRITE(method, &bound->recv, recv);
 | 
			
		||||
    RB_OBJ_WRITE(method, &bound->klass, data->klass);
 | 
			
		||||
    RB_OBJ_WRITE(method, &bound->me, rb_method_entry_clone(data->me));
 | 
			
		||||
    rclass = CLASS_OF(recv);
 | 
			
		||||
    if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) {
 | 
			
		||||
	VALUE ic = rb_class_search_ancestor(rclass, bound->defined_class);
 | 
			
		||||
 | 
			
		||||
    if (RB_TYPE_P(bound->me->owner, T_MODULE)) {
 | 
			
		||||
	VALUE ic = rb_class_search_ancestor(klass, bound->me->owner);
 | 
			
		||||
	if (ic) {
 | 
			
		||||
	    rclass = ic;
 | 
			
		||||
	    klass = ic;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    rclass = rb_include_class_new(methclass, rclass);
 | 
			
		||||
	    klass = rb_include_class_new(methclass, klass);
 | 
			
		||||
	}
 | 
			
		||||
	RB_OBJ_WRITE(method, &bound->me, rb_method_entry_complement_defined_class(bound->me, klass));
 | 
			
		||||
    }
 | 
			
		||||
    bound->recv = recv;
 | 
			
		||||
    bound->rclass = rclass;
 | 
			
		||||
 | 
			
		||||
    return method;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2150,14 +2146,12 @@ method_arity(VALUE method)
 | 
			
		|||
static const rb_method_entry_t *
 | 
			
		||||
original_method_entry(VALUE mod, ID id)
 | 
			
		||||
{
 | 
			
		||||
    VALUE rclass;
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    while ((me = rb_method_entry(mod, id, &rclass)) != 0) {
 | 
			
		||||
    while ((me = rb_method_entry(mod, id)) != 0) {
 | 
			
		||||
	const rb_method_definition_t *def = me->def;
 | 
			
		||||
	if (!def) break;
 | 
			
		||||
	if (def->type != VM_METHOD_TYPE_ZSUPER) break;
 | 
			
		||||
	mod = RCLASS_SUPER(rclass);
 | 
			
		||||
	mod = RCLASS_SUPER(me->owner);
 | 
			
		||||
	id = def->original_id;
 | 
			
		||||
    }
 | 
			
		||||
    return me;
 | 
			
		||||
| 
						 | 
				
			
			@ -2322,6 +2316,7 @@ method_inspect(VALUE method)
 | 
			
		|||
    const char *s;
 | 
			
		||||
    const char *sharp = "#";
 | 
			
		||||
    VALUE mklass;
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
 | 
			
		||||
    TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
 | 
			
		||||
    str = rb_str_buf_new2("#<");
 | 
			
		||||
| 
						 | 
				
			
			@ -2329,7 +2324,19 @@ method_inspect(VALUE method)
 | 
			
		|||
    rb_str_buf_cat2(str, s);
 | 
			
		||||
    rb_str_buf_cat2(str, ": ");
 | 
			
		||||
 | 
			
		||||
    mklass = data->me->klass;
 | 
			
		||||
    mklass = data->klass;
 | 
			
		||||
 | 
			
		||||
    if (data->me && data->me->def->type == VM_METHOD_TYPE_ALIAS) {
 | 
			
		||||
	defined_class = data->me->def->body.alias.original_me->owner;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	defined_class = data->me->defined_class ? data->me->defined_class : data->me->owner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (RB_TYPE_P(defined_class, T_ICLASS)) {
 | 
			
		||||
	defined_class = RBASIC_CLASS(defined_class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (FL_TEST(mklass, FL_SINGLETON)) {
 | 
			
		||||
	VALUE v = rb_ivar_get(mklass, attached);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2349,16 +2356,16 @@ method_inspect(VALUE method)
 | 
			
		|||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	rb_str_buf_append(str, rb_class_name(data->rclass));
 | 
			
		||||
	if (data->rclass != mklass) {
 | 
			
		||||
	rb_str_buf_append(str, rb_class_name(mklass));
 | 
			
		||||
	if (defined_class != mklass) {
 | 
			
		||||
	    rb_str_buf_cat2(str, "(");
 | 
			
		||||
	    rb_str_buf_append(str, rb_class_name(mklass));
 | 
			
		||||
	    rb_str_buf_append(str, rb_class_name(defined_class));
 | 
			
		||||
	    rb_str_buf_cat2(str, ")");
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    rb_str_buf_cat2(str, sharp);
 | 
			
		||||
    rb_str_append(str, rb_id2str(data->id));
 | 
			
		||||
    if (data->id != data->me->def->original_id) {
 | 
			
		||||
    rb_str_append(str, rb_id2str(data->me->called_id));
 | 
			
		||||
    if (data->me->called_id != data->me->def->original_id) {
 | 
			
		||||
	rb_str_catf(str, "(%"PRIsVALUE")",
 | 
			
		||||
		    rb_id2str(data->me->def->original_id));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2444,19 +2451,15 @@ static VALUE
 | 
			
		|||
method_super_method(VALUE method)
 | 
			
		||||
{
 | 
			
		||||
    const struct METHOD *data;
 | 
			
		||||
    VALUE defined_class, super_class;
 | 
			
		||||
    VALUE super_class;
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
 | 
			
		||||
    defined_class = data->defined_class;
 | 
			
		||||
    if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass;
 | 
			
		||||
    super_class = RCLASS_SUPER(defined_class);
 | 
			
		||||
    super_class = RCLASS_SUPER(data->me->defined_class);
 | 
			
		||||
    if (!super_class) return Qnil;
 | 
			
		||||
    me = rb_method_entry_without_refinements(super_class, data->id, &defined_class);
 | 
			
		||||
    me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, data->me->called_id);
 | 
			
		||||
    if (!me) return Qnil;
 | 
			
		||||
    return mnew_internal(me, defined_class,
 | 
			
		||||
			 super_class, data->recv, data->id,
 | 
			
		||||
			 rb_obj_class(method), FALSE, FALSE);
 | 
			
		||||
    return mnew_internal(me, super_class, data->recv, data->me->called_id, rb_obj_class(method), FALSE, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										99
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										99
									
								
								vm.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -8,6 +8,8 @@
 | 
			
		|||
 | 
			
		||||
**********************************************************************/
 | 
			
		||||
 | 
			
		||||
#define VM_CHECK_MODE 0
 | 
			
		||||
 | 
			
		||||
#include "internal.h"
 | 
			
		||||
#include "ruby/vm.h"
 | 
			
		||||
#include "ruby/st.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -128,10 +130,10 @@ static void vm_collect_usage_register(int reg, int isset);
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
 | 
			
		||||
vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self,
 | 
			
		||||
		  int argc, const VALUE *argv, const rb_block_t *blockptr);
 | 
			
		||||
static VALUE
 | 
			
		||||
vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
 | 
			
		||||
vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
 | 
			
		||||
	       int argc, const VALUE *argv, const rb_block_t *blockptr);
 | 
			
		||||
 | 
			
		||||
static rb_serial_t ruby_vm_global_method_state = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -253,8 +255,7 @@ vm_set_top_stack(rb_thread_t *th, VALUE iseqval)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /* for return */
 | 
			
		||||
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
 | 
			
		||||
		  th->top_self, rb_cObject,
 | 
			
		||||
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, th->top_self,
 | 
			
		||||
		  VM_ENVVAL_BLOCK_PTR(0),
 | 
			
		||||
		  (VALUE)vm_cref_new_toplevel(th), /* cref or me */
 | 
			
		||||
		  iseq->iseq_encoded, th->cfp->sp, iseq->local_size, iseq->stack_max);
 | 
			
		||||
| 
						 | 
				
			
			@ -267,8 +268,7 @@ vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const rb_cref_t *cref, rb_blo
 | 
			
		|||
    GetISeqPtr(iseqval, iseq);
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH,
 | 
			
		||||
		  base_block->self, base_block->klass,
 | 
			
		||||
		  VM_ENVVAL_PREV_EP_PTR(base_block->ep),
 | 
			
		||||
		  base_block->self, VM_ENVVAL_PREV_EP_PTR(base_block->ep),
 | 
			
		||||
		  (VALUE)cref, /* cref or me */
 | 
			
		||||
		  iseq->iseq_encoded,
 | 
			
		||||
		  th->cfp->sp, iseq->local_size, iseq->stack_max);
 | 
			
		||||
| 
						 | 
				
			
			@ -343,10 +343,10 @@ void
 | 
			
		|||
rb_vm_pop_cfunc_frame(void)
 | 
			
		||||
{
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
    const rb_method_entry_t *me = rb_vm_frame_method_entry(th->cfp);
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(th->cfp);
 | 
			
		||||
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->owner, Qnil);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
    vm_pop_frame(th);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -557,7 +557,6 @@ vm_make_env_each(const rb_thread_t *const th, rb_control_frame_t *const cfp,
 | 
			
		|||
 | 
			
		||||
    /* as Binding */
 | 
			
		||||
    env->block.self = cfp->self;
 | 
			
		||||
    env->block.klass = 0;
 | 
			
		||||
    env->block.ep = cfp->ep;
 | 
			
		||||
    env->block.iseq = cfp->iseq;
 | 
			
		||||
    env->block.proc = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -809,7 +808,7 @@ static inline VALUE
 | 
			
		|||
invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
			
		||||
		    VALUE self, int argc, const VALUE *argv,
 | 
			
		||||
		    const rb_block_t *blockptr, const rb_cref_t *cref,
 | 
			
		||||
		    VALUE defined_class, int splattable)
 | 
			
		||||
		    int splattable)
 | 
			
		||||
{
 | 
			
		||||
    if (SPECIAL_CONST_P(block->iseq)) {
 | 
			
		||||
	return Qnil;
 | 
			
		||||
| 
						 | 
				
			
			@ -820,7 +819,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
			
		|||
	const rb_control_frame_t *cfp;
 | 
			
		||||
	int i, opt_pc, arg_size = iseq->param.size;
 | 
			
		||||
	int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
 | 
			
		||||
	const rb_method_entry_t *me = th->passed_bmethod_me;
 | 
			
		||||
	const rb_callable_method_entry_t *me = th->passed_bmethod_me;
 | 
			
		||||
	th->passed_bmethod_me = NULL;
 | 
			
		||||
	cfp = th->cfp;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -833,20 +832,18 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
			
		|||
 | 
			
		||||
	if (me != 0) {
 | 
			
		||||
	    /* bmethod */
 | 
			
		||||
	    vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD,
 | 
			
		||||
			  self, defined_class,
 | 
			
		||||
	    vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD, self, 
 | 
			
		||||
			  VM_ENVVAL_PREV_EP_PTR(block->ep),
 | 
			
		||||
			  (VALUE)me, /* cref or method (TODO: can we ignore cref?) */
 | 
			
		||||
			  iseq->iseq_encoded + opt_pc,
 | 
			
		||||
			  cfp->sp + arg_size, iseq->local_size - arg_size,
 | 
			
		||||
			  iseq->stack_max);
 | 
			
		||||
 | 
			
		||||
	    RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
	    EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->klass, Qnil);
 | 
			
		||||
	    RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
	    EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->owner, Qnil);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
 | 
			
		||||
			  self, defined_class,
 | 
			
		||||
	    vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, self,
 | 
			
		||||
			  VM_ENVVAL_PREV_EP_PTR(block->ep),
 | 
			
		||||
			  (VALUE)cref, /* cref or method */
 | 
			
		||||
			  iseq->iseq_encoded + opt_pc,
 | 
			
		||||
| 
						 | 
				
			
			@ -858,15 +855,14 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
			
		|||
 | 
			
		||||
	if (me) {
 | 
			
		||||
	    /* bmethod */
 | 
			
		||||
	    EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->klass, ret);
 | 
			
		||||
	    RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
	    EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->owner, ret);
 | 
			
		||||
	    RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return vm_yield_with_cfunc(th, block, self, defined_class,
 | 
			
		||||
				   argc, argv, blockptr);
 | 
			
		||||
	return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -886,28 +882,25 @@ static inline VALUE
 | 
			
		|||
vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const rb_cref_t *cref)
 | 
			
		||||
{
 | 
			
		||||
    const rb_block_t *blockptr = check_block(th);
 | 
			
		||||
    return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref,
 | 
			
		||||
			       blockptr->klass, 1);
 | 
			
		||||
    return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline VALUE
 | 
			
		||||
vm_yield(rb_thread_t *th, int argc, const VALUE *argv)
 | 
			
		||||
{
 | 
			
		||||
    const rb_block_t *blockptr = check_block(th);
 | 
			
		||||
    return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0,
 | 
			
		||||
			       blockptr->klass, 1);
 | 
			
		||||
    return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline VALUE
 | 
			
		||||
vm_yield_with_block(rb_thread_t *th, int argc, const VALUE *argv, const rb_block_t *blockargptr)
 | 
			
		||||
{
 | 
			
		||||
    const rb_block_t *blockptr = check_block(th);
 | 
			
		||||
    return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, blockargptr, 0,
 | 
			
		||||
			       blockptr->klass, 1);
 | 
			
		||||
    return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, blockargptr, 0, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
 | 
			
		||||
vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
 | 
			
		||||
	       int argc, const VALUE *argv, const rb_block_t *blockptr)
 | 
			
		||||
{
 | 
			
		||||
    VALUE val = Qundef;
 | 
			
		||||
| 
						 | 
				
			
			@ -917,8 +910,7 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class
 | 
			
		|||
    TH_PUSH_TAG(th);
 | 
			
		||||
    if ((state = EXEC_TAG()) == 0) {
 | 
			
		||||
	th->safe_level = proc->safe_level;
 | 
			
		||||
	val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0,
 | 
			
		||||
				  defined_class, 0);
 | 
			
		||||
	val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
    TH_POP_TAG();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -931,11 +923,10 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
 | 
			
		||||
vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self,
 | 
			
		||||
		  int argc, const VALUE *argv, const rb_block_t *blockptr)
 | 
			
		||||
{
 | 
			
		||||
    return invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0,
 | 
			
		||||
			       defined_class, 0);
 | 
			
		||||
    return invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
| 
						 | 
				
			
			@ -943,12 +934,11 @@ rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc,
 | 
			
		|||
		  int argc, const VALUE *argv, const rb_block_t *blockptr)
 | 
			
		||||
{
 | 
			
		||||
    VALUE self = proc->block.self;
 | 
			
		||||
    VALUE defined_class = proc->block.klass;
 | 
			
		||||
    if (proc->is_from_method) {
 | 
			
		||||
	return vm_invoke_bmethod(th, proc, self, defined_class, argc, argv, blockptr);
 | 
			
		||||
	return vm_invoke_bmethod(th, proc, self, argc, argv, blockptr);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return vm_invoke_proc(th, proc, self, defined_class, argc, argv, blockptr);
 | 
			
		||||
	return vm_invoke_proc(th, proc, self, argc, argv, blockptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1260,12 +1250,12 @@ static int
 | 
			
		|||
check_redefined_method(st_data_t key, st_data_t value, st_data_t data)
 | 
			
		||||
{
 | 
			
		||||
    ID mid = (ID)key;
 | 
			
		||||
    rb_method_entry_t *me = (rb_method_entry_t *)value;
 | 
			
		||||
    VALUE klass = (VALUE)data;
 | 
			
		||||
    rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL);
 | 
			
		||||
    const rb_method_entry_t *me = (rb_method_entry_t *)value;
 | 
			
		||||
    const rb_method_entry_t *newme = rb_method_entry(klass, mid);
 | 
			
		||||
 | 
			
		||||
    if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner);
 | 
			
		||||
 | 
			
		||||
    if (newme != me)
 | 
			
		||||
	rb_vm_check_redefinition_opt_method(me, me->klass);
 | 
			
		||||
    return ST_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1280,7 +1270,7 @@ rb_vm_check_redefinition_by_prepend(VALUE klass)
 | 
			
		|||
static void
 | 
			
		||||
add_opt_method(VALUE klass, ID mid, VALUE bop)
 | 
			
		||||
{
 | 
			
		||||
    rb_method_entry_t *me = rb_method_entry_at(klass, mid);
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry_at(klass, mid);
 | 
			
		||||
 | 
			
		||||
    if (me && me->def->type == VM_METHOD_TYPE_CFUNC) {
 | 
			
		||||
	st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
 | 
			
		||||
| 
						 | 
				
			
			@ -1361,7 +1351,7 @@ hook_before_rewind(rb_thread_t *th, rb_control_frame_t *cfp)
 | 
			
		|||
	    EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
 | 
			
		||||
	    EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self,
 | 
			
		||||
					  rb_vm_frame_method_entry(th->cfp)->called_id,
 | 
			
		||||
					  rb_vm_frame_method_entry(th->cfp)->klass, Qnil);
 | 
			
		||||
					  rb_vm_frame_method_entry(th->cfp)->owner, Qnil);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
 | 
			
		||||
| 
						 | 
				
			
			@ -1508,8 +1498,10 @@ vm_exec(rb_thread_t *th)
 | 
			
		|||
	while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
 | 
			
		||||
	    if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) {
 | 
			
		||||
		EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self,
 | 
			
		||||
				rb_vm_frame_method_entry(th->cfp)->called_id, rb_vm_frame_method_entry(th->cfp)->klass, Qnil);
 | 
			
		||||
		RUBY_DTRACE_METHOD_RETURN_HOOK(th, rb_vm_frame_method_entry(th->cfp)->klass,
 | 
			
		||||
				rb_vm_frame_method_entry(th->cfp)->called_id,
 | 
			
		||||
				rb_vm_frame_method_entry(th->cfp)->owner, Qnil);
 | 
			
		||||
		RUBY_DTRACE_METHOD_RETURN_HOOK(th,
 | 
			
		||||
					       rb_vm_frame_method_entry(th->cfp)->owner,
 | 
			
		||||
					       rb_vm_frame_method_entry(th->cfp)->called_id);
 | 
			
		||||
	    }
 | 
			
		||||
	    th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
 | 
			
		||||
| 
						 | 
				
			
			@ -1673,7 +1665,7 @@ vm_exec(rb_thread_t *th)
 | 
			
		|||
	    /* push block frame */
 | 
			
		||||
	    cfp->sp[0] = (VALUE)err;
 | 
			
		||||
	    vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE,
 | 
			
		||||
			  cfp->self, cfp->klass,
 | 
			
		||||
			  cfp->self,
 | 
			
		||||
			  VM_ENVVAL_PREV_EP_PTR(cfp->ep),
 | 
			
		||||
			  0, /* cref or me */
 | 
			
		||||
			  catch_iseq->iseq_encoded,
 | 
			
		||||
| 
						 | 
				
			
			@ -1738,11 +1730,11 @@ rb_iseq_eval_main(VALUE iseqval)
 | 
			
		|||
int
 | 
			
		||||
rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
 | 
			
		||||
    if (me) {
 | 
			
		||||
	if (idp) *idp = me->def->original_id;
 | 
			
		||||
	if (klassp) *klassp = me->klass;
 | 
			
		||||
	if (klassp) *klassp = me->owner;
 | 
			
		||||
	return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1766,7 +1758,7 @@ VALUE
 | 
			
		|||
rb_thread_current_status(const rb_thread_t *th)
 | 
			
		||||
{
 | 
			
		||||
    const rb_control_frame_t *cfp = th->cfp;
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
    const rb_callable_method_entry_t *me;
 | 
			
		||||
    VALUE str = Qnil;
 | 
			
		||||
 | 
			
		||||
    if (cfp->iseq != 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1779,7 +1771,7 @@ rb_thread_current_status(const rb_thread_t *th)
 | 
			
		|||
    }
 | 
			
		||||
    else if ((me = rb_vm_frame_method_entry(cfp)) && me->def->original_id) {
 | 
			
		||||
	str = rb_sprintf("`%"PRIsVALUE"#%"PRIsVALUE"' (cfunc)",
 | 
			
		||||
			 rb_class_path(me->klass),
 | 
			
		||||
			 rb_class_path(me->owner),
 | 
			
		||||
			 rb_id2str(me->def->original_id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1796,7 +1788,7 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
 | 
			
		|||
    VALUE val;
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
 | 
			
		||||
		  recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr),
 | 
			
		||||
		  recv, VM_ENVVAL_BLOCK_PTR(blockptr),
 | 
			
		||||
		  (VALUE)vm_cref_new_toplevel(th), /* cref or me */
 | 
			
		||||
		  0, reg_cfp->sp, 1, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2073,7 +2065,6 @@ rb_thread_mark(void *ptr)
 | 
			
		|||
		rb_iseq_t *iseq = cfp->iseq;
 | 
			
		||||
		rb_gc_mark(cfp->proc);
 | 
			
		||||
		rb_gc_mark(cfp->self);
 | 
			
		||||
		rb_gc_mark(cfp->klass);
 | 
			
		||||
		if (iseq) {
 | 
			
		||||
		    rb_gc_mark(RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2231,7 +2222,7 @@ th_init(rb_thread_t *th, VALUE self)
 | 
			
		|||
    th->cfp = (void *)(th->stack + th->stack_size);
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_DUMMY | VM_FRAME_FLAG_FINISH /* dummy frame */,
 | 
			
		||||
		  Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0) /* dummy block ptr */,
 | 
			
		||||
		  Qnil /* dummy self */, VM_ENVVAL_BLOCK_PTR(0) /* dummy block ptr */,
 | 
			
		||||
		  0 /* dummy cref/me */,
 | 
			
		||||
		  0 /* dummy pc */, th->stack, 1, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2544,7 +2535,6 @@ Init_VM(void)
 | 
			
		|||
    rb_define_method_id(klass, idLambda, rb_block_lambda, 0);
 | 
			
		||||
    rb_obj_freeze(fcore);
 | 
			
		||||
    RBASIC_CLEAR_CLASS(klass);
 | 
			
		||||
    RCLASS_SET_SUPER(klass, 0);
 | 
			
		||||
    rb_obj_freeze(klass);
 | 
			
		||||
    rb_gc_register_mark_object(fcore);
 | 
			
		||||
    rb_mRubyVMFrozenCore = fcore;
 | 
			
		||||
| 
						 | 
				
			
			@ -2793,7 +2783,6 @@ Init_VM(void)
 | 
			
		|||
	th->cfp->iseq = iseq;
 | 
			
		||||
	th->cfp->pc = iseq->iseq_encoded;
 | 
			
		||||
	th->cfp->self = th->top_self;
 | 
			
		||||
	th->cfp->klass = Qnil;
 | 
			
		||||
 | 
			
		||||
	th->cfp->ep[-1] = (VALUE)vm_cref_new(rb_cObject, METHOD_VISI_PRIVATE, NULL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -689,7 +689,7 @@ raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc)
 | 
			
		|||
    VALUE at;
 | 
			
		||||
 | 
			
		||||
    if (iseq) {
 | 
			
		||||
	vm_push_frame(th, iseq, VM_FRAME_MAGIC_DUMMY, Qnil /* self */, Qnil /* klass */,
 | 
			
		||||
	vm_push_frame(th, iseq, VM_FRAME_MAGIC_DUMMY, Qnil /* self */,
 | 
			
		||||
		      VM_ENVVAL_BLOCK_PTR(0) /* specval*/, Qfalse /* me or cref */,
 | 
			
		||||
		      iseq->iseq_encoded, th->cfp->sp, 1 /* local_size (cref/me) */, 0 /* stack_max */);
 | 
			
		||||
	at = rb_vm_backtrace_object();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -465,7 +465,7 @@ backtrace_each(rb_thread_t *th,
 | 
			
		|||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
 | 
			
		||||
	    const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
	    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
	    ID mid = me->def->original_id;
 | 
			
		||||
 | 
			
		||||
	    iter_cfunc(arg, cfp, mid);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								vm_core.h
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								vm_core.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -183,8 +183,7 @@ typedef struct rb_call_info_struct {
 | 
			
		|||
    VALUE klass;
 | 
			
		||||
 | 
			
		||||
    /* inline cache: values */
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    const rb_callable_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    /* temporary values for method calling */
 | 
			
		||||
    struct rb_block_struct *blockptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -524,7 +523,7 @@ typedef struct rb_vm_struct {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef VM_DEBUG_VERIFY_METHOD_CACHE
 | 
			
		||||
#define VM_DEBUG_VERIFY_METHOD_CACHE 0
 | 
			
		||||
#define VM_DEBUG_VERIFY_METHOD_CACHE (VM_DEBUG_MODE != 0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct rb_control_frame_struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -533,10 +532,9 @@ typedef struct rb_control_frame_struct {
 | 
			
		|||
    rb_iseq_t *iseq;		/* cfp[2] */
 | 
			
		||||
    VALUE flag;			/* cfp[3] */
 | 
			
		||||
    VALUE self;			/* cfp[4] / block[0] */
 | 
			
		||||
    VALUE klass;		/* cfp[5] / block[1] */
 | 
			
		||||
    VALUE *ep;			/* cfp[6] / block[2] */
 | 
			
		||||
    rb_iseq_t *block_iseq;	/* cfp[7] / block[3] */
 | 
			
		||||
    VALUE proc;			/* cfp[8] / block[4] */
 | 
			
		||||
    VALUE *ep;			/* cfp[6] / block[1] */
 | 
			
		||||
    rb_iseq_t *block_iseq;	/* cfp[7] / block[2] */
 | 
			
		||||
    VALUE proc;			/* cfp[8] / block[3] */
 | 
			
		||||
 | 
			
		||||
#if VM_DEBUG_BP_CHECK
 | 
			
		||||
    VALUE *bp_check;		/* cfp[9] */
 | 
			
		||||
| 
						 | 
				
			
			@ -545,7 +543,6 @@ typedef struct rb_control_frame_struct {
 | 
			
		|||
 | 
			
		||||
typedef struct rb_block_struct {
 | 
			
		||||
    VALUE self;			/* share with method frame if it's only block */
 | 
			
		||||
    VALUE klass;		/* share with method frame if it's only block */
 | 
			
		||||
    VALUE *ep;			/* share with method frame if it's only block */
 | 
			
		||||
    rb_iseq_t *iseq;
 | 
			
		||||
    VALUE proc;
 | 
			
		||||
| 
						 | 
				
			
			@ -631,7 +628,7 @@ typedef struct rb_thread_struct {
 | 
			
		|||
    const rb_block_t *passed_block;
 | 
			
		||||
 | 
			
		||||
    /* for bmethod */
 | 
			
		||||
    const rb_method_entry_t *passed_bmethod_me;
 | 
			
		||||
    const rb_callable_method_entry_t *passed_bmethod_me;
 | 
			
		||||
 | 
			
		||||
    /* for cfunc */
 | 
			
		||||
    rb_call_info_t *passed_ci;
 | 
			
		||||
| 
						 | 
				
			
			@ -976,8 +973,7 @@ VALUE *rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynva
 | 
			
		|||
void rb_vm_inc_const_missing_count(void);
 | 
			
		||||
void rb_vm_gvl_destroy(rb_vm_t *vm);
 | 
			
		||||
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc,
 | 
			
		||||
		 const VALUE *argv, const rb_method_entry_t *me,
 | 
			
		||||
		 VALUE defined_class);
 | 
			
		||||
		 const VALUE *argv, const rb_callable_method_entry_t *me);
 | 
			
		||||
 | 
			
		||||
void rb_thread_start_timer_thread(void);
 | 
			
		||||
void rb_thread_stop_timer_thread(int);
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,7 +1020,7 @@ int rb_autoloading_value(VALUE mod, ID id, VALUE* value);
 | 
			
		|||
 | 
			
		||||
void rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr);
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
 | 
			
		||||
const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
 | 
			
		||||
 | 
			
		||||
#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
 | 
			
		|||
    const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
 | 
			
		||||
    VALUE tmp;
 | 
			
		||||
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
    const rb_callable_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    if (cfp->block_iseq != 0 && !RUBY_VM_IFUNC_P(cfp->block_iseq)) {
 | 
			
		||||
	biseq_name = "";	/* RSTRING(cfp->block_iseq->location.label)->ptr; */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										111
									
								
								vm_eval.c
									
										
									
									
									
								
							
							
						
						
									
										111
									
								
								vm_eval.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -42,15 +42,13 @@ static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type sc
 | 
			
		|||
static VALUE vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv);
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
vm_call0(rb_thread_t* th, VALUE recv, ID id, int argc, const VALUE *argv,
 | 
			
		||||
	 const rb_method_entry_t *me, VALUE defined_class)
 | 
			
		||||
vm_call0(rb_thread_t* th, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    rb_call_info_t ci_entry, *ci = &ci_entry;
 | 
			
		||||
 | 
			
		||||
    ci->flag = 0;
 | 
			
		||||
    ci->mid = id;
 | 
			
		||||
    ci->recv = recv;
 | 
			
		||||
    ci->defined_class = defined_class;
 | 
			
		||||
    ci->argc = argc;
 | 
			
		||||
    ci->me = me;
 | 
			
		||||
    ci->kw_arg = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -64,11 +62,11 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		|||
{
 | 
			
		||||
    VALUE val;
 | 
			
		||||
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->defined_class, ci->mid);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class, Qnil);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->me->owner, ci->mid);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->me->owner, Qnil);
 | 
			
		||||
    {
 | 
			
		||||
	rb_control_frame_t *reg_cfp = th->cfp;
 | 
			
		||||
	const rb_method_entry_t *me = ci->me;
 | 
			
		||||
	const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
	const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
 | 
			
		||||
	int len = cfunc->argc;
 | 
			
		||||
	VALUE recv = ci->recv;
 | 
			
		||||
| 
						 | 
				
			
			@ -95,8 +93,8 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		|||
	    vm_pop_frame(th);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->defined_class, ci->mid);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->me->owner, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->me->owner, ci->mid);
 | 
			
		||||
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -105,21 +103,20 @@ static VALUE
 | 
			
		|||
vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		||||
{
 | 
			
		||||
    VALUE val;
 | 
			
		||||
    const rb_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
 | 
			
		||||
    int len = cfunc->argc;
 | 
			
		||||
    VALUE recv = ci->recv;
 | 
			
		||||
    VALUE defined_class = ci->defined_class;
 | 
			
		||||
    int argc = ci->argc;
 | 
			
		||||
    ID mid = ci->mid;
 | 
			
		||||
    rb_block_t *blockptr = ci->blockptr;
 | 
			
		||||
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, defined_class, mid);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, defined_class, Qnil);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, mid);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, me->owner, Qnil);
 | 
			
		||||
    {
 | 
			
		||||
	rb_control_frame_t *reg_cfp = th->cfp;
 | 
			
		||||
 | 
			
		||||
	vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
 | 
			
		||||
	vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, 
 | 
			
		||||
		      VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me,
 | 
			
		||||
		      0, reg_cfp->sp, 1, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -134,8 +131,8 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv
 | 
			
		|||
	VM_PROFILE_UP(3);
 | 
			
		||||
	vm_pop_frame(th);
 | 
			
		||||
    }
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, defined_class, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, defined_class, mid);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, me->owner, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, mid);
 | 
			
		||||
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -198,14 +195,16 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		|||
      case VM_METHOD_TYPE_REFINED:
 | 
			
		||||
	{
 | 
			
		||||
	    const rb_method_type_t type = ci->me->def->type;
 | 
			
		||||
	    VALUE super_class;
 | 
			
		||||
 | 
			
		||||
	    if (type == VM_METHOD_TYPE_REFINED && ci->me->def->body.refined.orig_me) {
 | 
			
		||||
		ci->me = ci->me->def->body.refined.orig_me;
 | 
			
		||||
		ci->me = refined_method_callable_without_refinement(ci->me);
 | 
			
		||||
		goto again;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    ci->defined_class = RCLASS_SUPER(ci->defined_class);
 | 
			
		||||
	    super_class = RCLASS_SUPER(ci->me->defined_class);
 | 
			
		||||
 | 
			
		||||
	    if (!ci->defined_class || !(ci->me = rb_method_entry(ci->defined_class, ci->mid, &ci->defined_class))) {
 | 
			
		||||
	    if (!super_class || !(ci->me = rb_callable_method_entry(super_class, ci->mid))) {
 | 
			
		||||
		enum method_missing_reason ex = (type == VM_METHOD_TYPE_ZSUPER) ? MISSING_SUPER : 0;
 | 
			
		||||
		ret = method_missing(ci->recv, ci->mid, ci->argc, argv, ex);
 | 
			
		||||
		goto success;
 | 
			
		||||
| 
						 | 
				
			
			@ -214,11 +213,8 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		|||
	    goto again;
 | 
			
		||||
	}
 | 
			
		||||
      case VM_METHOD_TYPE_ALIAS:
 | 
			
		||||
	{
 | 
			
		||||
	    ci->me = ci->me->def->body.alias.original_me;
 | 
			
		||||
	    ci->defined_class = find_defined_class_by_owner(ci->defined_class, ci->me->klass);
 | 
			
		||||
	    goto again;
 | 
			
		||||
	}
 | 
			
		||||
	ci->me = aliased_callable_method_entry(ci->me);
 | 
			
		||||
	goto again;
 | 
			
		||||
      case VM_METHOD_TYPE_MISSING:
 | 
			
		||||
	{
 | 
			
		||||
	    VALUE new_args = rb_ary_new4(ci->argc, argv);
 | 
			
		||||
| 
						 | 
				
			
			@ -258,10 +254,9 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
 | 
			
		||||
	   const rb_method_entry_t *me, VALUE defined_class)
 | 
			
		||||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    return vm_call0(th, recv, id, argc, argv, me, defined_class);
 | 
			
		||||
    return vm_call0(th, recv, id, argc, argv, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline VALUE
 | 
			
		||||
| 
						 | 
				
			
			@ -270,22 +265,24 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
 | 
			
		|||
    VALUE recv = th->cfp->self;
 | 
			
		||||
    VALUE klass;
 | 
			
		||||
    ID id;
 | 
			
		||||
    rb_method_entry_t *me;
 | 
			
		||||
    rb_control_frame_t *cfp = th->cfp;
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
 | 
			
		||||
 | 
			
		||||
    if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) || NIL_P(cfp->klass)) {
 | 
			
		||||
    if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
 | 
			
		||||
	rb_bug("vm_call_super: should not be reached");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    klass = RCLASS_ORIGIN(cfp->klass);
 | 
			
		||||
    klass = RCLASS_ORIGIN(me->defined_class);
 | 
			
		||||
    klass = RCLASS_SUPER(klass);
 | 
			
		||||
    id = rb_vm_frame_method_entry(cfp)->def->original_id;
 | 
			
		||||
    me = rb_method_entry(klass, id, &klass);
 | 
			
		||||
    id = me->def->original_id;
 | 
			
		||||
    me = rb_callable_method_entry(klass, id);
 | 
			
		||||
 | 
			
		||||
    if (!me) {
 | 
			
		||||
	return method_missing(recv, id, argc, argv, MISSING_SUPER);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return vm_call0(th, recv, id, argc, argv, me, klass);
 | 
			
		||||
    else {
 | 
			
		||||
	return vm_call0(th, recv, id, argc, argv, me);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
| 
						 | 
				
			
			@ -316,9 +313,8 @@ stack_check(void)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline rb_method_entry_t *
 | 
			
		||||
    rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
 | 
			
		||||
static inline enum method_missing_reason rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self);
 | 
			
		||||
static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE recv, ID mid);
 | 
			
		||||
static inline enum method_missing_reason rb_method_call_status(rb_thread_t *th, const rb_callable_method_entry_t *me, call_type scope, VALUE self);
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \internal
 | 
			
		||||
| 
						 | 
				
			
			@ -339,9 +335,7 @@ static inline VALUE
 | 
			
		|||
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
 | 
			
		||||
	 call_type scope, VALUE self)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    rb_method_entry_t *me =
 | 
			
		||||
	rb_search_method_entry(recv, mid, &defined_class);
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_search_method_entry(recv, mid);
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
    enum method_missing_reason call_status = rb_method_call_status(th, me, scope, self);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -349,7 +343,7 @@ rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
 | 
			
		|||
	return method_missing(recv, mid, argc, argv, call_status);
 | 
			
		||||
    }
 | 
			
		||||
    stack_check();
 | 
			
		||||
    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 | 
			
		||||
    return vm_call0(th, recv, mid, argc, argv, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rescue_funcall_args {
 | 
			
		||||
| 
						 | 
				
			
			@ -384,13 +378,12 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e)
 | 
			
		|||
static int
 | 
			
		||||
check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(klass, idRespond_to, &defined_class);
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_callable_method_entry(klass, idRespond_to);
 | 
			
		||||
 | 
			
		||||
    if (me && !METHOD_ENTRY_BASIC(me)) {
 | 
			
		||||
	const rb_block_t *passed_block = th->passed_block;
 | 
			
		||||
	VALUE args[2], result;
 | 
			
		||||
	int arity = rb_method_entry_arity(me);
 | 
			
		||||
	int arity = rb_method_entry_arity((const rb_method_entry_t *)me);
 | 
			
		||||
 | 
			
		||||
	if (arity > 2)
 | 
			
		||||
	    rb_raise(rb_eArgError, "respond_to? must accept 1 or 2 arguments (requires %d)", arity);
 | 
			
		||||
| 
						 | 
				
			
			@ -399,7 +392,7 @@ check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
 | 
			
		|||
 | 
			
		||||
	args[0] = ID2SYM(mid);
 | 
			
		||||
	args[1] = Qtrue;
 | 
			
		||||
	result = vm_call0(th, recv, idRespond_to, arity, args, me, defined_class);
 | 
			
		||||
	result = vm_call0(th, recv, idRespond_to, arity, args, me);
 | 
			
		||||
	th->passed_block = passed_block;
 | 
			
		||||
	if (!RTEST(result)) {
 | 
			
		||||
	    return FALSE;
 | 
			
		||||
| 
						 | 
				
			
			@ -409,7 +402,7 @@ check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
check_funcall_callable(rb_thread_t *th, const rb_method_entry_t *me)
 | 
			
		||||
check_funcall_callable(rb_thread_t *th, const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    return rb_method_call_status(th, me, CALL_FCALL, th->cfp->self) == MISSING_NONE;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -438,19 +431,18 @@ VALUE
 | 
			
		|||
rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
 | 
			
		||||
{
 | 
			
		||||
    VALUE klass = CLASS_OF(recv);
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
    const rb_callable_method_entry_t *me;
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
 | 
			
		||||
    if (!check_funcall_respond_to(th, klass, recv, mid))
 | 
			
		||||
	return Qundef;
 | 
			
		||||
 | 
			
		||||
    me = rb_search_method_entry(recv, mid, &defined_class);
 | 
			
		||||
    me = rb_search_method_entry(recv, mid);
 | 
			
		||||
    if (!check_funcall_callable(th, me)) {
 | 
			
		||||
	return check_funcall_missing(th, klass, recv, mid, argc, argv);
 | 
			
		||||
    }
 | 
			
		||||
    stack_check();
 | 
			
		||||
    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 | 
			
		||||
    return vm_call0(th, recv, mid, argc, argv, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
| 
						 | 
				
			
			@ -458,21 +450,20 @@ rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv,
 | 
			
		|||
			   rb_check_funcall_hook *hook, VALUE arg)
 | 
			
		||||
{
 | 
			
		||||
    VALUE klass = CLASS_OF(recv);
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
    const rb_callable_method_entry_t *me;
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
 | 
			
		||||
    if (!check_funcall_respond_to(th, klass, recv, mid))
 | 
			
		||||
	return Qundef;
 | 
			
		||||
 | 
			
		||||
    me = rb_search_method_entry(recv, mid, &defined_class);
 | 
			
		||||
    me = rb_search_method_entry(recv, mid);
 | 
			
		||||
    if (!check_funcall_callable(th, me)) {
 | 
			
		||||
	(*hook)(FALSE, recv, mid, argc, argv, arg);
 | 
			
		||||
	return check_funcall_missing(th, klass, recv, mid, argc, argv);
 | 
			
		||||
    }
 | 
			
		||||
    stack_check();
 | 
			
		||||
    (*hook)(TRUE, recv, mid, argc, argv, arg);
 | 
			
		||||
    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 | 
			
		||||
    return vm_call0(th, recv, mid, argc, argv, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *
 | 
			
		||||
| 
						 | 
				
			
			@ -511,8 +502,8 @@ rb_type_str(enum ruby_value_type type)
 | 
			
		|||
#undef type_case
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline rb_method_entry_t *
 | 
			
		||||
rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
 | 
			
		||||
static inline const rb_callable_method_entry_t *
 | 
			
		||||
rb_search_method_entry(VALUE recv, ID mid)
 | 
			
		||||
{
 | 
			
		||||
    VALUE klass = CLASS_OF(recv);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -550,11 +541,11 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
 | 
			
		|||
                         rb_id2str(mid), type, (void *)recv, flags);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return rb_method_entry(klass, mid, defined_class_ptr);
 | 
			
		||||
    return rb_callable_method_entry(klass, mid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum method_missing_reason
 | 
			
		||||
rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self)
 | 
			
		||||
rb_method_call_status(rb_thread_t *th, const rb_callable_method_entry_t *me, call_type scope, VALUE self)
 | 
			
		||||
{
 | 
			
		||||
    VALUE klass;
 | 
			
		||||
    ID oid;
 | 
			
		||||
| 
						 | 
				
			
			@ -565,10 +556,11 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc
 | 
			
		|||
	return scope == CALL_VCALL ? MISSING_VCALL : MISSING_NOENTRY;
 | 
			
		||||
    }
 | 
			
		||||
    if (me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	me = rb_resolve_refined_method(Qnil, me, NULL);
 | 
			
		||||
	me = rb_resolve_refined_method_callable(Qnil, me);
 | 
			
		||||
	if (UNDEFINED_METHOD_ENTRY_P(me)) goto undefined;
 | 
			
		||||
    }
 | 
			
		||||
    klass = me->klass;
 | 
			
		||||
 | 
			
		||||
    klass = me->owner;
 | 
			
		||||
    oid = me->def->original_id;
 | 
			
		||||
    visi = METHOD_ENTRY_VISI(me);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1306,7 +1298,6 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_
 | 
			
		|||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	vm_set_eval_stack(th, iseqval, cref, base_block);
 | 
			
		||||
	th->cfp->klass = CLASS_OF(base_block->self);
 | 
			
		||||
	RB_GC_GUARD(crefval);
 | 
			
		||||
 | 
			
		||||
	if (0) {		/* for debug */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										250
									
								
								vm_insnhelper.c
									
										
									
									
									
								
							
							
						
						
									
										250
									
								
								vm_insnhelper.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -22,8 +22,7 @@
 | 
			
		|||
#define INLINE inline
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static rb_control_frame_t *
 | 
			
		||||
vm_get_ruby_level_caller_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp);
 | 
			
		||||
static rb_control_frame_t *vm_get_ruby_level_caller_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp);
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
ruby_vm_sysstack_error_copy(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +39,34 @@ vm_stackoverflow(void)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#if VM_CHECK_MODE > 0
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
callable_class_p(VALUE klass)
 | 
			
		||||
{
 | 
			
		||||
#if VM_CHECK_MODE >= 2
 | 
			
		||||
    while (klass) {
 | 
			
		||||
	if (klass == rb_cBasicObject) {
 | 
			
		||||
	    return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
	klass = RCLASS_SUPER(klass);
 | 
			
		||||
    }
 | 
			
		||||
    return FALSE;
 | 
			
		||||
#else
 | 
			
		||||
    return klass != 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
callable_method_entry_p(const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    if (me == NULL || callable_class_p(me->defined_class)) {
 | 
			
		||||
	return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
check_frame(int magic, int req_block, int req_me, int req_cref, VALUE specval, VALUE cref_or_me)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +103,14 @@ check_frame(int magic, int req_block, int req_me, int req_cref, VALUE specval, V
 | 
			
		|||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cref_or_me_type == imemo_ment) {
 | 
			
		||||
	const rb_callable_method_entry_t *me = (const rb_callable_method_entry_t *)cref_or_me;
 | 
			
		||||
 | 
			
		||||
	if (!callable_method_entry_p(me)) {
 | 
			
		||||
	    rb_bug("vm_push_frame: ment (%s) should be callable on %x frame.", rb_obj_info(cref_or_me), magic);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +119,6 @@ vm_push_frame(rb_thread_t *th,
 | 
			
		|||
	      const rb_iseq_t *iseq,
 | 
			
		||||
	      VALUE type,
 | 
			
		||||
	      VALUE self,
 | 
			
		||||
	      VALUE klass,
 | 
			
		||||
	      VALUE specval,
 | 
			
		||||
	      VALUE cref_or_me,
 | 
			
		||||
	      const VALUE *pc,
 | 
			
		||||
| 
						 | 
				
			
			@ -147,19 +181,6 @@ vm_push_frame(rb_thread_t *th,
 | 
			
		|||
    cfp->block_iseq = 0;
 | 
			
		||||
    cfp->proc = 0;
 | 
			
		||||
 | 
			
		||||
    if (klass) {
 | 
			
		||||
	cfp->klass = klass;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
 | 
			
		||||
	if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) {
 | 
			
		||||
	    cfp->klass = Qnil;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    cfp->klass = prev_cfp->klass;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (VMDEBUG == 2) {
 | 
			
		||||
	SDR();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -334,7 +355,7 @@ vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type)
 | 
			
		|||
    return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rb_method_entry_t *
 | 
			
		||||
static rb_callable_method_entry_t *
 | 
			
		||||
check_method_entry(VALUE obj, int can_be_svar)
 | 
			
		||||
{
 | 
			
		||||
    if (obj == Qfalse) return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -345,7 +366,7 @@ check_method_entry(VALUE obj, int can_be_svar)
 | 
			
		|||
 | 
			
		||||
    switch (imemo_type(obj)) {
 | 
			
		||||
      case imemo_ment:
 | 
			
		||||
	return (rb_method_entry_t *)obj;
 | 
			
		||||
	return (rb_callable_method_entry_t *)obj;
 | 
			
		||||
      case imemo_cref:
 | 
			
		||||
	return NULL;
 | 
			
		||||
      case imemo_svar:
 | 
			
		||||
| 
						 | 
				
			
			@ -360,11 +381,11 @@ check_method_entry(VALUE obj, int can_be_svar)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
const rb_callable_method_entry_t *
 | 
			
		||||
rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
 | 
			
		||||
{
 | 
			
		||||
    VALUE *ep = cfp->ep;
 | 
			
		||||
    rb_method_entry_t *me;
 | 
			
		||||
    rb_callable_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    while (!VM_EP_LEP_P(ep)) {
 | 
			
		||||
	if ((me = check_method_entry(ep[-1], FALSE)) != NULL) return me;
 | 
			
		||||
| 
						 | 
				
			
			@ -375,7 +396,7 @@ rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static rb_cref_t *
 | 
			
		||||
method_entry_cref(rb_method_entry_t *me)
 | 
			
		||||
method_entry_cref(rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    switch (me->def->type) {
 | 
			
		||||
      case VM_METHOD_TYPE_ISEQ:
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +417,7 @@ check_cref(VALUE obj, int can_be_svar)
 | 
			
		|||
 | 
			
		||||
    switch (imemo_type(obj)) {
 | 
			
		||||
      case imemo_ment:
 | 
			
		||||
	return method_entry_cref((rb_method_entry_t *)obj);
 | 
			
		||||
	return method_entry_cref((rb_callable_method_entry_t *)obj);
 | 
			
		||||
      case imemo_cref:
 | 
			
		||||
	return (rb_cref_t *)obj;
 | 
			
		||||
      case imemo_svar:
 | 
			
		||||
| 
						 | 
				
			
			@ -558,15 +579,7 @@ vm_check_if_namespace(VALUE klass)
 | 
			
		|||
static inline VALUE
 | 
			
		||||
vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
 | 
			
		||||
{
 | 
			
		||||
    if (RB_TYPE_P(klass, T_MODULE) &&
 | 
			
		||||
	FL_TEST(klass, RMODULE_IS_OVERLAID) &&
 | 
			
		||||
	RB_TYPE_P(cfp->klass, T_ICLASS) &&
 | 
			
		||||
	RBASIC(cfp->klass)->klass == klass) {
 | 
			
		||||
	return cfp->klass;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return klass;
 | 
			
		||||
    }
 | 
			
		||||
    return klass;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline VALUE
 | 
			
		||||
| 
						 | 
				
			
			@ -1040,7 +1053,8 @@ vm_search_method(rb_call_info_t *ci, VALUE recv)
 | 
			
		|||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
 | 
			
		||||
    ci->me = rb_callable_method_entry(klass, ci->mid);
 | 
			
		||||
    VM_ASSERT(callable_method_entry_p(ci->me));
 | 
			
		||||
    ci->klass = klass;
 | 
			
		||||
    ci->call = vm_call_general;
 | 
			
		||||
#if OPT_INLINE_METHOD_CACHE
 | 
			
		||||
| 
						 | 
				
			
			@ -1050,7 +1064,7 @@ vm_search_method(rb_call_info_t *ci, VALUE recv)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static inline int
 | 
			
		||||
check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
 | 
			
		||||
check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)())
 | 
			
		||||
{
 | 
			
		||||
    if (me && me->def->type == VM_METHOD_TYPE_CFUNC &&
 | 
			
		||||
	me->def->body.cfunc.func == func) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1114,12 +1128,11 @@ rb_equal_opt(VALUE obj1, VALUE obj2)
 | 
			
		|||
    ci.klass = 0;
 | 
			
		||||
    ci.method_state = 0;
 | 
			
		||||
    ci.me = NULL;
 | 
			
		||||
    ci.defined_class = 0;
 | 
			
		||||
    ci.class_serial = 0;
 | 
			
		||||
    return opt_eq_func(obj1, obj2, &ci);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_method_entry_t*, VALUE);
 | 
			
		||||
static VALUE vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *);
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
 | 
			
		||||
| 
						 | 
				
			
			@ -1133,10 +1146,9 @@ check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
 | 
			
		|||
	}
 | 
			
		||||
	/* fall through */
 | 
			
		||||
      case VM_CHECKMATCH_TYPE_CASE: {
 | 
			
		||||
	VALUE defined_class;
 | 
			
		||||
	const rb_method_entry_t *me = rb_method_entry_with_refinements(CLASS_OF(pattern), idEqq, &defined_class);
 | 
			
		||||
	const rb_callable_method_entry_t *me = rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq);
 | 
			
		||||
	if (me) {
 | 
			
		||||
	    return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me, defined_class);
 | 
			
		||||
	    return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    /* fallback to funcall (e.g. method_missing) */
 | 
			
		||||
| 
						 | 
				
			
			@ -1352,7 +1364,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
 | 
			
		|||
{
 | 
			
		||||
    int i, local_size;
 | 
			
		||||
    VALUE *argv = cfp->sp - ci->argc;
 | 
			
		||||
    const rb_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
    rb_iseq_t *iseq = def_iseq_ptr(me->def);
 | 
			
		||||
    VALUE *sp = argv + iseq->param.size;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1361,7 +1373,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
 | 
			
		|||
	*sp++ = Qnil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class,
 | 
			
		||||
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv,
 | 
			
		||||
		  VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me,
 | 
			
		||||
		  iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, iseq->stack_max);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1374,7 +1386,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
 | 
			
		|||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    VALUE *argv = cfp->sp - ci->argc;
 | 
			
		||||
    const rb_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
    rb_iseq_t *iseq = def_iseq_ptr(me->def);
 | 
			
		||||
    VALUE *src_argv = argv;
 | 
			
		||||
    VALUE *sp_orig, *sp;
 | 
			
		||||
| 
						 | 
				
			
			@ -1401,8 +1413,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag,
 | 
			
		||||
		  ci->recv, ci->defined_class,
 | 
			
		||||
		  VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me,
 | 
			
		||||
		  ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me,
 | 
			
		||||
		  iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, iseq->stack_max);
 | 
			
		||||
 | 
			
		||||
    cfp->sp = sp_orig;
 | 
			
		||||
| 
						 | 
				
			
			@ -1541,7 +1552,7 @@ vm_profile_show_result(void)
 | 
			
		|||
 | 
			
		||||
static inline
 | 
			
		||||
const rb_method_cfunc_t *
 | 
			
		||||
vm_method_cfunc_entry(const rb_method_entry_t *me)
 | 
			
		||||
vm_method_cfunc_entry(const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
#if VM_DEBUG_VERIFY_METHOD_CACHE
 | 
			
		||||
    switch (me->def->type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1571,20 +1582,19 @@ static VALUE
 | 
			
		|||
vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
 | 
			
		||||
{
 | 
			
		||||
    VALUE val;
 | 
			
		||||
    const rb_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_method_cfunc_t *cfunc = vm_method_cfunc_entry(me);
 | 
			
		||||
    int len = cfunc->argc;
 | 
			
		||||
 | 
			
		||||
    /* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */
 | 
			
		||||
    VALUE recv = ci->recv;
 | 
			
		||||
    VALUE defined_class = ci->defined_class;
 | 
			
		||||
    rb_block_t *blockptr = ci->blockptr;
 | 
			
		||||
    int argc = ci->argc;
 | 
			
		||||
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->owner, Qundef);
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, NULL, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
 | 
			
		||||
    vm_push_frame(th, NULL, VM_FRAME_MAGIC_CFUNC, recv,
 | 
			
		||||
		  VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me,
 | 
			
		||||
		  0, th->cfp->sp, 1, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1600,8 +1610,8 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i
 | 
			
		|||
 | 
			
		||||
    vm_pop_frame(th);
 | 
			
		||||
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->owner, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1644,15 +1654,15 @@ static VALUE
 | 
			
		|||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
 | 
			
		||||
{
 | 
			
		||||
    VALUE val;
 | 
			
		||||
    const rb_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
    int len = vm_method_cfunc_entry(me)->argc;
 | 
			
		||||
    VALUE recv = ci->recv;
 | 
			
		||||
 | 
			
		||||
    CALLER_SETUP_ARG(reg_cfp, ci);
 | 
			
		||||
    if (len >= 0) rb_check_arity(ci->argc, len, len);
 | 
			
		||||
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->owner, Qnil);
 | 
			
		||||
 | 
			
		||||
    if (!(ci->me->def->flag & METHOD_VISI_PROTECTED) &&
 | 
			
		||||
	!(ci->flag & VM_CALL_ARGS_SPLAT) &&
 | 
			
		||||
| 
						 | 
				
			
			@ -1661,8 +1671,8 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
 | 
			
		|||
    }
 | 
			
		||||
    val = vm_call_cfunc_latter(th, reg_cfp, ci);
 | 
			
		||||
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
 | 
			
		||||
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->owner, val);
 | 
			
		||||
    RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id);
 | 
			
		||||
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1671,11 +1681,11 @@ void
 | 
			
		|||
rb_vm_call_cfunc_push_frame(rb_thread_t *th)
 | 
			
		||||
{
 | 
			
		||||
    rb_call_info_t *ci = th->passed_ci;
 | 
			
		||||
    const rb_method_entry_t *me = ci->me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = ci->me;
 | 
			
		||||
    th->passed_ci = 0;
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
 | 
			
		||||
		  VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me /* cref */,
 | 
			
		||||
    vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
 | 
			
		||||
		  ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me /* cref */,
 | 
			
		||||
		  0, th->cfp->sp + ci->aux.inc_sp, 1, 0);
 | 
			
		||||
 | 
			
		||||
    if (ci->call != vm_call_general) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1716,7 +1726,7 @@ vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv)
 | 
			
		|||
    /* control block frame */
 | 
			
		||||
    th->passed_bmethod_me = ci->me;
 | 
			
		||||
    GetProcPtr(ci->me->def->body.proc, proc);
 | 
			
		||||
    val = vm_invoke_bmethod(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr);
 | 
			
		||||
    val = vm_invoke_bmethod(th, proc, ci->recv, ci->argc, argv, ci->blockptr);
 | 
			
		||||
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1790,7 +1800,7 @@ vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *c
 | 
			
		|||
	ci->argc -= 1;
 | 
			
		||||
	DEC_SP(1);
 | 
			
		||||
    }
 | 
			
		||||
    ci->me = rb_method_entry_without_refinements(CLASS_OF(ci->recv), ci->mid, &ci->defined_class);
 | 
			
		||||
    ci->me = rb_callable_method_entry_without_refinements(CLASS_OF(ci->recv), ci->mid);
 | 
			
		||||
 | 
			
		||||
    ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1828,7 +1838,7 @@ vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
 | 
			
		|||
    ci_entry.mid = idMethodMissing;
 | 
			
		||||
    ci_entry.blockptr = ci->blockptr;
 | 
			
		||||
    ci_entry.recv = ci->recv;
 | 
			
		||||
    ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class);
 | 
			
		||||
    ci_entry.me = rb_callable_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing);
 | 
			
		||||
    ci_entry.kw_arg = NULL;
 | 
			
		||||
 | 
			
		||||
    /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
 | 
			
		||||
| 
						 | 
				
			
			@ -1892,6 +1902,55 @@ find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
 | 
			
		|||
    return current_class; /* maybe module function */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rb_method_definition_t *method_definition_create(rb_method_type_t type, ID mid);
 | 
			
		||||
static void method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts);
 | 
			
		||||
 | 
			
		||||
static const rb_callable_method_entry_t *
 | 
			
		||||
aliased_callable_method_entry(const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *orig_me = me->def->body.alias.original_me;
 | 
			
		||||
    const rb_callable_method_entry_t *cme;
 | 
			
		||||
 | 
			
		||||
    if (orig_me->defined_class == 0) {
 | 
			
		||||
	VALUE defined_class = find_defined_class_by_owner(me->defined_class, orig_me->owner);
 | 
			
		||||
	VM_ASSERT(RB_TYPE_P(orig_me->owner, T_MODULE));
 | 
			
		||||
	cme = rb_method_entry_complement_defined_class(orig_me, defined_class);
 | 
			
		||||
 | 
			
		||||
	if (me->def->alias_count == 0) {
 | 
			
		||||
	    RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    method_definition_set((rb_method_entry_t *)me,
 | 
			
		||||
				  method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id),
 | 
			
		||||
				  (void *)cme);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	cme = (const rb_callable_method_entry_t *)orig_me;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VM_ASSERT(callable_method_entry_p(cme));
 | 
			
		||||
    return cme;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const rb_callable_method_entry_t *
 | 
			
		||||
refined_method_callable_without_refinement(const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *orig_me = me->def->body.refined.orig_me;
 | 
			
		||||
    const rb_callable_method_entry_t *cme;
 | 
			
		||||
 | 
			
		||||
    if (orig_me->defined_class == 0) {
 | 
			
		||||
	cme = NULL;
 | 
			
		||||
	rb_notimplement();
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	cme = (const rb_callable_method_entry_t *)orig_me;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VM_ASSERT(callable_method_entry_p(cme));
 | 
			
		||||
    return cme;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
__forceinline
 | 
			
		||||
| 
						 | 
				
			
			@ -1904,12 +1963,16 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
    int enable_fastpath = 1;
 | 
			
		||||
    rb_call_info_t ci_temp;
 | 
			
		||||
 | 
			
		||||
    VM_ASSERT(callable_method_entry_p(ci->me));
 | 
			
		||||
 | 
			
		||||
  start_method_dispatch:
 | 
			
		||||
    VM_ASSERT(callable_method_entry_p(ci->me));
 | 
			
		||||
    if (ci->me != 0) {
 | 
			
		||||
	if (LIKELY(METHOD_ENTRY_VISI(ci->me) == METHOD_VISI_PUBLIC && METHOD_ENTRY_SAFE(ci->me) == 0)) {
 | 
			
		||||
	    VALUE klass;
 | 
			
		||||
 | 
			
		||||
	  normal_method_dispatch:
 | 
			
		||||
	    VM_ASSERT(callable_method_entry_p(ci->me));
 | 
			
		||||
	    switch (ci->me->def->type) {
 | 
			
		||||
	      case VM_METHOD_TYPE_ISEQ:{
 | 
			
		||||
		CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath);
 | 
			
		||||
| 
						 | 
				
			
			@ -1943,7 +2006,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
		return vm_call_bmethod(th, cfp, ci);
 | 
			
		||||
	      }
 | 
			
		||||
	      case VM_METHOD_TYPE_ZSUPER:{
 | 
			
		||||
		klass = ci->me->klass;
 | 
			
		||||
		klass = ci->me->owner;
 | 
			
		||||
		klass = RCLASS_ORIGIN(klass);
 | 
			
		||||
	      zsuper_method_dispatch:
 | 
			
		||||
		klass = RCLASS_SUPER(klass);
 | 
			
		||||
| 
						 | 
				
			
			@ -1954,7 +2017,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
		ci_temp = *ci;
 | 
			
		||||
		ci = &ci_temp;
 | 
			
		||||
 | 
			
		||||
		ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
 | 
			
		||||
		ci->me = rb_callable_method_entry(klass, ci->mid);
 | 
			
		||||
 | 
			
		||||
		if (ci->me != 0) {
 | 
			
		||||
		    goto normal_method_dispatch;
 | 
			
		||||
| 
						 | 
				
			
			@ -1963,11 +2026,9 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
		    goto start_method_dispatch;
 | 
			
		||||
		}
 | 
			
		||||
	      }
 | 
			
		||||
	      case VM_METHOD_TYPE_ALIAS: {
 | 
			
		||||
		ci->me = ci->me->def->body.alias.original_me;
 | 
			
		||||
		ci->defined_class = find_defined_class_by_owner(ci->defined_class, ci->me->klass /* owner */);
 | 
			
		||||
	      case VM_METHOD_TYPE_ALIAS:
 | 
			
		||||
		ci->me = aliased_callable_method_entry(ci->me);
 | 
			
		||||
		goto normal_method_dispatch;
 | 
			
		||||
	      }
 | 
			
		||||
	      case VM_METHOD_TYPE_OPTIMIZED:{
 | 
			
		||||
		switch (ci->me->def->body.optimize_type) {
 | 
			
		||||
		  case OPTIMIZED_METHOD_TYPE_SEND:
 | 
			
		||||
| 
						 | 
				
			
			@ -1987,26 +2048,24 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
	      case VM_METHOD_TYPE_REFINED:{
 | 
			
		||||
		const rb_cref_t *cref = rb_vm_get_cref(cfp->ep);
 | 
			
		||||
		VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
 | 
			
		||||
		VALUE refinement, defined_class;
 | 
			
		||||
		rb_method_entry_t *me;
 | 
			
		||||
		VALUE refinement;
 | 
			
		||||
		const rb_callable_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
		refinement = find_refinement(refinements,
 | 
			
		||||
					     ci->defined_class);
 | 
			
		||||
		refinement = find_refinement(refinements, ci->me->owner);
 | 
			
		||||
		if (NIL_P(refinement)) {
 | 
			
		||||
		    goto no_refinement_dispatch;
 | 
			
		||||
		}
 | 
			
		||||
		me = rb_method_entry(refinement, ci->mid, &defined_class);
 | 
			
		||||
		me = rb_callable_method_entry(refinement, ci->mid);
 | 
			
		||||
		if (me) {
 | 
			
		||||
		    if (ci->call == vm_call_super_method) {
 | 
			
		||||
			const rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
 | 
			
		||||
			const rb_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
 | 
			
		||||
			const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
 | 
			
		||||
 | 
			
		||||
			if (top_me && rb_method_definition_eq(me->def, top_me->def)) {
 | 
			
		||||
			    goto no_refinement_dispatch;
 | 
			
		||||
			}
 | 
			
		||||
		    }
 | 
			
		||||
		    ci->me = me;
 | 
			
		||||
		    ci->defined_class = defined_class;
 | 
			
		||||
		    if (me->def->type != VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
			goto start_method_dispatch;
 | 
			
		||||
		    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2018,14 +2077,15 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
 | 
			
		||||
	      no_refinement_dispatch:
 | 
			
		||||
		if (ci->me->def->body.refined.orig_me) {
 | 
			
		||||
		    ci->me = ci->me->def->body.refined.orig_me;
 | 
			
		||||
		    ci->me = refined_method_callable_without_refinement(ci->me);
 | 
			
		||||
 | 
			
		||||
		    if (UNDEFINED_METHOD_ENTRY_P(ci->me)) {
 | 
			
		||||
			ci->me = 0;
 | 
			
		||||
		    }
 | 
			
		||||
		    goto start_method_dispatch;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		    klass = ci->me->klass;
 | 
			
		||||
		    klass = ci->me->owner;
 | 
			
		||||
		    goto zsuper_method_dispatch;
 | 
			
		||||
		}
 | 
			
		||||
	      }
 | 
			
		||||
| 
						 | 
				
			
			@ -2045,7 +2105,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 | 
			
		|||
	    }
 | 
			
		||||
	    else if (!(ci->flag & VM_CALL_OPT_SEND) && (METHOD_ENTRY_VISI(ci->me) == METHOD_VISI_PROTECTED)) {
 | 
			
		||||
		enable_fastpath = 0;
 | 
			
		||||
		if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) {
 | 
			
		||||
		if (!rb_obj_is_kind_of(cfp->self, ci->me->defined_class)) {
 | 
			
		||||
		    ci->aux.method_missing_reason = MISSING_PROTECTED;
 | 
			
		||||
		    return vm_call_method_missing(th, cfp, ci);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2113,7 +2173,7 @@ vm_super_outside(void)
 | 
			
		|||
static int
 | 
			
		||||
vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me;
 | 
			
		||||
    const rb_callable_method_entry_t *me;
 | 
			
		||||
 | 
			
		||||
    while (iseq && !iseq->klass) {
 | 
			
		||||
	iseq = iseq->parent_iseq;
 | 
			
		||||
| 
						 | 
				
			
			@ -2157,10 +2217,11 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	ci->mid = me->def->original_id;
 | 
			
		||||
	ci->klass = vm_search_normal_superclass(lcfp->klass);
 | 
			
		||||
	ci->klass = vm_search_normal_superclass(me->defined_class);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	ci->klass = vm_search_normal_superclass(reg_cfp->klass);
 | 
			
		||||
	me = rb_vm_frame_method_entry(reg_cfp);
 | 
			
		||||
	ci->klass = vm_search_normal_superclass(me->defined_class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2172,12 +2233,14 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
 | 
			
		|||
    VALUE current_defined_class;
 | 
			
		||||
    rb_iseq_t *iseq = GET_ISEQ();
 | 
			
		||||
    VALUE sigval = TOPN(ci->argc);
 | 
			
		||||
    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp);
 | 
			
		||||
 | 
			
		||||
    current_defined_class = GET_CFP()->klass;
 | 
			
		||||
    if (NIL_P(current_defined_class)) {
 | 
			
		||||
    if (!me) {
 | 
			
		||||
	vm_super_outside();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    current_defined_class = me->defined_class;
 | 
			
		||||
 | 
			
		||||
    if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) {
 | 
			
		||||
	current_defined_class = RCLASS_REFINED_CLASS(current_defined_class);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2212,7 +2275,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /* TODO: use inline cache */
 | 
			
		||||
    ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
 | 
			
		||||
    ci->me = rb_callable_method_entry(ci->klass, ci->mid);
 | 
			
		||||
    ci->call = vm_call_super_method;
 | 
			
		||||
 | 
			
		||||
    while (iseq && !iseq->klass) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2220,8 +2283,8 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && def_iseq_ptr(ci->me->def) == iseq) {
 | 
			
		||||
	ci->klass = RCLASS_SUPER(ci->defined_class);
 | 
			
		||||
	ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
 | 
			
		||||
	ci->klass = RCLASS_SUPER(ci->me->defined_class);
 | 
			
		||||
	ci->me = rb_callable_method_entry(ci->klass, ci->mid);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2242,15 +2305,14 @@ block_proc_is_lambda(const VALUE procval)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static inline VALUE
 | 
			
		||||
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
 | 
			
		||||
		    VALUE self, VALUE defined_class,
 | 
			
		||||
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, VALUE self,
 | 
			
		||||
		    int argc, const VALUE *argv,
 | 
			
		||||
		    const rb_block_t *blockargptr)
 | 
			
		||||
{
 | 
			
		||||
    const struct vm_ifunc *ifunc = (struct vm_ifunc *)block->iseq;
 | 
			
		||||
    VALUE val, arg, blockarg;
 | 
			
		||||
    int lambda = block_proc_is_lambda(block->proc);
 | 
			
		||||
    const rb_method_entry_t *me = th->passed_bmethod_me;
 | 
			
		||||
    const rb_callable_method_entry_t *me = th->passed_bmethod_me;
 | 
			
		||||
    th->passed_bmethod_me = NULL;
 | 
			
		||||
 | 
			
		||||
    if (lambda) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2276,8 +2338,7 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC,
 | 
			
		||||
		  self, defined_class,
 | 
			
		||||
		  VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me,
 | 
			
		||||
		  self, VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me,
 | 
			
		||||
		  0, th->cfp->sp, 1, 0);
 | 
			
		||||
 | 
			
		||||
    val = (*ifunc->func) (arg, ifunc->data, argc, argv, blockarg);
 | 
			
		||||
| 
						 | 
				
			
			@ -2332,7 +2393,6 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
 | 
			
		|||
	vm_push_frame(th, iseq,
 | 
			
		||||
		      is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK,
 | 
			
		||||
		      block->self,
 | 
			
		||||
		      block->klass,
 | 
			
		||||
		      VM_ENVVAL_PREV_EP_PTR(block->ep), 0,
 | 
			
		||||
		      iseq->iseq_encoded + opt_pc,
 | 
			
		||||
		      rsp + arg_size,
 | 
			
		||||
| 
						 | 
				
			
			@ -2343,7 +2403,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
 | 
			
		|||
    else {
 | 
			
		||||
	VALUE val;
 | 
			
		||||
	CALLER_SETUP_ARG(th->cfp, ci);
 | 
			
		||||
	val = vm_yield_with_cfunc(th, block, block->self, block->klass,
 | 
			
		||||
	val = vm_yield_with_cfunc(th, block, block->self,
 | 
			
		||||
				  ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0);
 | 
			
		||||
	POPN(ci->argc); /* TODO: should put before C/yield? */
 | 
			
		||||
	return val;
 | 
			
		||||
| 
						 | 
				
			
			@ -2461,7 +2521,7 @@ vm_defined(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE
 | 
			
		|||
	break;
 | 
			
		||||
      case DEFINED_METHOD:{
 | 
			
		||||
	VALUE klass = CLASS_OF(v);
 | 
			
		||||
	const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0);
 | 
			
		||||
	const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj));
 | 
			
		||||
 | 
			
		||||
	if (me) {
 | 
			
		||||
	    switch (METHOD_ENTRY_VISI(me)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										322
									
								
								vm_method.c
									
										
									
									
									
								
							
							
						
						
									
										322
									
								
								vm_method.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -93,6 +93,15 @@ rb_clear_method_cache_by_class(VALUE klass)
 | 
			
		|||
	else {
 | 
			
		||||
	    rb_class_clear_method_cache(klass, Qnil);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (RB_TYPE_P(klass, T_MODULE)) {
 | 
			
		||||
	    rb_subclass_entry_t *entry = RCLASS_EXT(klass)->subclasses;
 | 
			
		||||
 | 
			
		||||
	    for (; entry != NULL; entry = entry->next) {
 | 
			
		||||
		struct st_table *table = RCLASS_CALLABLE_M_TBL(entry->klass);
 | 
			
		||||
		if (table) st_clear(table);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -201,7 +210,7 @@ setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
 | 
			
		||||
method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
 | 
			
		||||
{
 | 
			
		||||
    *(rb_method_definition_t **)&me->def = def;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -263,8 +272,12 @@ method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *
 | 
			
		|||
	    def->body.optimize_type = (enum method_optimized_type)opts;
 | 
			
		||||
	    return;
 | 
			
		||||
	  case VM_METHOD_TYPE_REFINED:
 | 
			
		||||
	    RB_OBJ_WRITE(me, &def->body.refined.orig_me, (rb_method_entry_t *)opts);
 | 
			
		||||
	    return;
 | 
			
		||||
	    {
 | 
			
		||||
		const rb_method_refined_t *refined = (rb_method_refined_t *)opts;
 | 
			
		||||
		RB_OBJ_WRITE(me, &def->body.refined.orig_me, refined->orig_me);
 | 
			
		||||
		RB_OBJ_WRITE(me, &def->body.refined.owner, refined->owner);
 | 
			
		||||
		return;
 | 
			
		||||
	    }
 | 
			
		||||
	  case VM_METHOD_TYPE_ALIAS:
 | 
			
		||||
	    RB_OBJ_WRITE(me, &def->body.alias.original_me, (rb_method_entry_t *)opts);
 | 
			
		||||
	    return;
 | 
			
		||||
| 
						 | 
				
			
			@ -273,7 +286,6 @@ method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *
 | 
			
		|||
	  case VM_METHOD_TYPE_MISSING:
 | 
			
		||||
	    return;
 | 
			
		||||
	}
 | 
			
		||||
	rb_bug("rb_add_method: unsupported method type (%d)\n", def->type);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +308,7 @@ method_definition_reset(const rb_method_entry_t *me)
 | 
			
		|||
	break;
 | 
			
		||||
      case VM_METHOD_TYPE_REFINED:
 | 
			
		||||
	RB_OBJ_WRITTEN(me, Qundef, def->body.refined.orig_me);
 | 
			
		||||
	RB_OBJ_WRITTEN(me, Qundef, def->body.refined.owner);
 | 
			
		||||
	break;
 | 
			
		||||
      case VM_METHOD_TYPE_ALIAS:
 | 
			
		||||
	RB_OBJ_WRITTEN(me, Qundef, def->body.alias.original_me);
 | 
			
		||||
| 
						 | 
				
			
			@ -328,46 +341,83 @@ method_definition_addref(rb_method_definition_t *def)
 | 
			
		|||
    return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rb_method_entry_t *
 | 
			
		||||
rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def)
 | 
			
		||||
{
 | 
			
		||||
    rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, owner, defined_class);
 | 
			
		||||
    return me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
filter_defined_class(VALUE klass)
 | 
			
		||||
{
 | 
			
		||||
    switch (BUILTIN_TYPE(klass)) {
 | 
			
		||||
      case T_CLASS:
 | 
			
		||||
	return klass;
 | 
			
		||||
      case T_MODULE:
 | 
			
		||||
	return 0;
 | 
			
		||||
      case T_ICLASS:
 | 
			
		||||
	break;
 | 
			
		||||
    }
 | 
			
		||||
    rb_bug("filter_defined_class: %s", rb_obj_info(klass));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rb_method_entry_t *
 | 
			
		||||
rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def)
 | 
			
		||||
{
 | 
			
		||||
    rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, (VALUE)klass, 0);
 | 
			
		||||
    rb_method_entry_t *me = rb_method_entry_alloc(called_id, klass, filter_defined_class(klass), def);
 | 
			
		||||
    METHOD_ENTRY_FLAGS_SET(me, visi, ruby_running ? FALSE : TRUE, rb_safe_level());
 | 
			
		||||
    if (def != NULL) method_definition_reset(me);
 | 
			
		||||
    return me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rb_method_entry_t *
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_method_entry_clone(const rb_method_entry_t *src_me)
 | 
			
		||||
{
 | 
			
		||||
    rb_method_entry_t *me = rb_method_entry_create(src_me->called_id, src_me->klass,
 | 
			
		||||
						   METHOD_ENTRY_VISI(src_me),
 | 
			
		||||
						   method_definition_addref(src_me->def));
 | 
			
		||||
    rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class,
 | 
			
		||||
						  method_definition_addref(src_me->def));
 | 
			
		||||
    METHOD_ENTRY_FLAGS_COPY(me, src_me);
 | 
			
		||||
    return me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_callable_method_entry_t *
 | 
			
		||||
rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, VALUE defined_class)
 | 
			
		||||
{
 | 
			
		||||
    rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, defined_class,
 | 
			
		||||
						  method_definition_addref(src_me->def));
 | 
			
		||||
    METHOD_ENTRY_FLAGS_COPY(me, src_me);
 | 
			
		||||
    return (rb_callable_method_entry_t *)me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src)
 | 
			
		||||
{
 | 
			
		||||
    *(rb_method_definition_t **)&dst->def = method_definition_addref(src->def);
 | 
			
		||||
    method_definition_reset(dst);
 | 
			
		||||
    dst->called_id = src->called_id;
 | 
			
		||||
    RB_OBJ_WRITE((VALUE)dst, &dst->klass, src->klass);
 | 
			
		||||
    RB_OBJ_WRITE((VALUE)dst, &dst->owner, src->owner);
 | 
			
		||||
    RB_OBJ_WRITE((VALUE)dst, &dst->defined_class, src->defined_class);
 | 
			
		||||
    METHOD_ENTRY_FLAGS_COPY(dst, src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
make_method_entry_refined(rb_method_entry_t *me)
 | 
			
		||||
make_method_entry_refined(VALUE owner, rb_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    if (me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	rb_method_entry_t *cloned_me;
 | 
			
		||||
	struct {
 | 
			
		||||
	    const struct rb_method_entry_struct *orig_me;
 | 
			
		||||
	    VALUE owner;
 | 
			
		||||
	} refined;
 | 
			
		||||
 | 
			
		||||
	rb_vm_check_redefinition_opt_method(me, me->klass);
 | 
			
		||||
	cloned_me = rb_method_entry_clone(me);
 | 
			
		||||
	rb_vm_check_redefinition_opt_method(me, me->owner);
 | 
			
		||||
 | 
			
		||||
	method_definition_set(me, method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id), (void *)cloned_me);
 | 
			
		||||
	refined.orig_me = rb_method_entry_clone(me);
 | 
			
		||||
	refined.owner = owner;
 | 
			
		||||
 | 
			
		||||
	method_definition_set(me, method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id), (void *)&refined);
 | 
			
		||||
	METHOD_ENTRY_VISI_SET(me, METHOD_VISI_PUBLIC);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +428,7 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid)
 | 
			
		|||
    rb_method_entry_t *me = lookup_method_table(refined_class, mid);
 | 
			
		||||
 | 
			
		||||
    if (me) {
 | 
			
		||||
	make_method_entry_refined(me);
 | 
			
		||||
	make_method_entry_refined(refined_class, me);
 | 
			
		||||
	rb_clear_method_cache_by_class(refined_class);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
| 
						 | 
				
			
			@ -490,7 +540,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (make_refined) {
 | 
			
		||||
	make_method_entry_refined(me);
 | 
			
		||||
	make_method_entry_refined(klass, me);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    st_insert(mtbl, mid, (st_data_t) me);
 | 
			
		||||
| 
						 | 
				
			
			@ -607,7 +657,7 @@ search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
 | 
			
		|||
    return me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rb_method_entry_t *
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_method_entry_at(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    return lookup_method_table(klass, id);
 | 
			
		||||
| 
						 | 
				
			
			@ -619,9 +669,9 @@ rb_method_entry_at(VALUE klass, ID id)
 | 
			
		|||
 * if you need method entry with method cache (normal case), use
 | 
			
		||||
 * rb_method_entry() simply.
 | 
			
		||||
 */
 | 
			
		||||
rb_method_entry_t *
 | 
			
		||||
rb_method_entry_get_without_cache(VALUE klass, ID id,
 | 
			
		||||
				  VALUE *defined_class_ptr)
 | 
			
		||||
static rb_method_entry_t *
 | 
			
		||||
method_entry_get_without_cache(VALUE klass, ID id,
 | 
			
		||||
			       VALUE *defined_class_ptr)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    rb_method_entry_t *me = search_method(klass, id, &defined_class);
 | 
			
		||||
| 
						 | 
				
			
			@ -659,7 +709,7 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *
 | 
			
		|||
{
 | 
			
		||||
    VALUE actual_defined_class;
 | 
			
		||||
    rb_method_entry_t *actual_me =
 | 
			
		||||
	rb_method_entry_get_without_cache(klass, id, &actual_defined_class);
 | 
			
		||||
      method_entry_get_without_cache(klass, id, &actual_defined_class);
 | 
			
		||||
 | 
			
		||||
    if (me != actual_me || defined_class != actual_defined_class) {
 | 
			
		||||
	rb_bug("method cache verification failed");
 | 
			
		||||
| 
						 | 
				
			
			@ -667,8 +717,8 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
rb_method_entry_t *
 | 
			
		||||
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
 | 
			
		||||
static rb_method_entry_t *
 | 
			
		||||
method_entry_get(VALUE klass, ID id, VALUE *defined_class_ptr)
 | 
			
		||||
{
 | 
			
		||||
#if OPT_GLOBAL_METHOD_CACHE
 | 
			
		||||
    struct cache_entry *ent;
 | 
			
		||||
| 
						 | 
				
			
			@ -676,107 +726,182 @@ rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
 | 
			
		|||
    if (ent->method_state == GET_GLOBAL_METHOD_STATE() &&
 | 
			
		||||
	ent->class_serial == RCLASS_SERIAL(klass) &&
 | 
			
		||||
	ent->mid == id) {
 | 
			
		||||
	if (defined_class_ptr)
 | 
			
		||||
	    *defined_class_ptr = ent->defined_class;
 | 
			
		||||
#if VM_DEBUG_VERIFY_METHOD_CACHE
 | 
			
		||||
	verify_method_cache(klass, id, ent->defined_class, ent->me);
 | 
			
		||||
#endif
 | 
			
		||||
	if (defined_class_ptr) *defined_class_ptr = ent->defined_class;
 | 
			
		||||
	return ent->me;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const rb_method_entry_t *
 | 
			
		||||
get_original_method_entry(VALUE refinements,
 | 
			
		||||
			  const rb_method_entry_t *me,
 | 
			
		||||
			  VALUE *defined_class_ptr)
 | 
			
		||||
{
 | 
			
		||||
    VALUE super;
 | 
			
		||||
 | 
			
		||||
    if (me->def->body.refined.orig_me) {
 | 
			
		||||
	return me->def->body.refined.orig_me;
 | 
			
		||||
    }
 | 
			
		||||
    else if (!(super = RCLASS_SUPER(me->klass))) {
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	rb_method_entry_t *tmp_me;
 | 
			
		||||
	tmp_me = rb_method_entry(super, me->called_id,
 | 
			
		||||
				 defined_class_ptr);
 | 
			
		||||
	return rb_resolve_refined_method(refinements, tmp_me,
 | 
			
		||||
					 defined_class_ptr);
 | 
			
		||||
    }
 | 
			
		||||
    return method_entry_get_without_cache(klass, id, defined_class_ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me,
 | 
			
		||||
			  VALUE *defined_class_ptr)
 | 
			
		||||
rb_method_entry(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	VALUE refinement;
 | 
			
		||||
	rb_method_entry_t *tmp_me;
 | 
			
		||||
    return method_entry_get(klass, id, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	refinement = find_refinement(refinements, me->klass);
 | 
			
		||||
	if (NIL_P(refinement)) {
 | 
			
		||||
	    return get_original_method_entry(refinements, me,
 | 
			
		||||
					     defined_class_ptr);
 | 
			
		||||
static const rb_callable_method_entry_t *
 | 
			
		||||
prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    struct st_table *mtbl;
 | 
			
		||||
    const rb_callable_method_entry_t *cme;
 | 
			
		||||
 | 
			
		||||
    if (me && me->defined_class == 0) {
 | 
			
		||||
	VM_ASSERT(RB_TYPE_P(defined_class, T_ICLASS));
 | 
			
		||||
	VM_ASSERT(me->defined_class == 0);
 | 
			
		||||
 | 
			
		||||
	if ((mtbl = RCLASS_EXT(defined_class)->callable_m_tbl) == NULL) {
 | 
			
		||||
	    mtbl = RCLASS_EXT(defined_class)->callable_m_tbl = st_init_numtable();
 | 
			
		||||
	}
 | 
			
		||||
	tmp_me = rb_method_entry(refinement, me->called_id,
 | 
			
		||||
				 defined_class_ptr);
 | 
			
		||||
	if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	    return tmp_me;
 | 
			
		||||
 | 
			
		||||
	if (st_lookup(mtbl, id, (st_data_t *)&me)) {
 | 
			
		||||
	    cme = (rb_callable_method_entry_t *)me;
 | 
			
		||||
	    VM_ASSERT(callable_method_entry_p(cme));
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    return get_original_method_entry(refinements, me,
 | 
			
		||||
					     defined_class_ptr);
 | 
			
		||||
	    cme = rb_method_entry_complement_defined_class(me, defined_class);
 | 
			
		||||
	    st_insert(mtbl, id, (st_data_t)cme);
 | 
			
		||||
	    VM_ASSERT(callable_method_entry_p(cme));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return (rb_method_entry_t *)me;
 | 
			
		||||
	cme = (const rb_callable_method_entry_t *)me;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VM_ASSERT(callable_method_entry_p(cme));
 | 
			
		||||
    return cme;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_method_entry_with_refinements(VALUE klass, ID id,
 | 
			
		||||
				 VALUE *defined_class_ptr)
 | 
			
		||||
const rb_callable_method_entry_t *
 | 
			
		||||
rb_callable_method_entry(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
 | 
			
		||||
    rb_method_entry_t *me = method_entry_get(klass, id, &defined_class);
 | 
			
		||||
    return prepare_callable_method_entry(defined_class, id, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	const rb_cref_t *cref = rb_vm_cref();
 | 
			
		||||
	VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
 | 
			
		||||
static const rb_method_entry_t *resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr);
 | 
			
		||||
 | 
			
		||||
	me = rb_resolve_refined_method(refinements, me, &defined_class);
 | 
			
		||||
static const rb_method_entry_t *
 | 
			
		||||
method_entry_resolve_refienment(VALUE klass, ID id, int with_refinement, VALUE *defined_class_ptr)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me = method_entry_get(klass, id, defined_class_ptr);
 | 
			
		||||
 | 
			
		||||
    if (me) {
 | 
			
		||||
	if (me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	    if (with_refinement) {
 | 
			
		||||
		const rb_cref_t *cref = rb_vm_cref();
 | 
			
		||||
		VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
 | 
			
		||||
		me = resolve_refined_method(refinements, me, defined_class_ptr);
 | 
			
		||||
	    }
 | 
			
		||||
	    else {
 | 
			
		||||
		me = resolve_refined_method(Qnil, me, defined_class_ptr);
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    if (UNDEFINED_METHOD_ENTRY_P(me)) me = NULL;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (defined_class_ptr) *defined_class_ptr = defined_class;
 | 
			
		||||
 | 
			
		||||
    return me;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_method_entry_without_refinements(VALUE klass, ID id,
 | 
			
		||||
				    VALUE *defined_class_ptr)
 | 
			
		||||
rb_method_entry_with_refinements(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    return method_entry_resolve_refienment(klass, id, TRUE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_callable_method_entry_t *
 | 
			
		||||
rb_callable_method_entry_with_refinements(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
 | 
			
		||||
    const rb_method_entry_t *me = method_entry_resolve_refienment(klass, id, TRUE, &defined_class);
 | 
			
		||||
    return prepare_callable_method_entry(defined_class, id, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	me = rb_resolve_refined_method(Qnil, me, &defined_class);
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_method_entry_without_refinements(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    return method_entry_resolve_refienment(klass, id, FALSE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_callable_method_entry_t *
 | 
			
		||||
rb_callable_method_entry_without_refinements(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class;
 | 
			
		||||
    const rb_method_entry_t *me = method_entry_resolve_refienment(klass, id, FALSE, &defined_class);
 | 
			
		||||
    return prepare_callable_method_entry(defined_class, id, me);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const rb_method_entry_t *
 | 
			
		||||
refiend_method_original_method_entry(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
 | 
			
		||||
{
 | 
			
		||||
    VALUE super;
 | 
			
		||||
 | 
			
		||||
    if (me->def->body.refined.orig_me) {
 | 
			
		||||
	if (defined_class_ptr) *defined_class_ptr = me->def->body.refined.orig_me->defined_class;
 | 
			
		||||
	return me->def->body.refined.orig_me;
 | 
			
		||||
    }
 | 
			
		||||
    if (defined_class_ptr)
 | 
			
		||||
	*defined_class_ptr = defined_class;
 | 
			
		||||
    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 | 
			
		||||
    else if (!(super = RCLASS_SUPER(me->owner))) {
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	rb_method_entry_t *tmp_me;
 | 
			
		||||
	tmp_me = method_entry_get(super, me->called_id, defined_class_ptr);
 | 
			
		||||
	return resolve_refined_method(refinements, tmp_me, defined_class_ptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const rb_method_entry_t *
 | 
			
		||||
resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	VALUE refinement;
 | 
			
		||||
	rb_method_entry_t *tmp_me;
 | 
			
		||||
 | 
			
		||||
	refinement = find_refinement(refinements, me->owner);
 | 
			
		||||
	if (NIL_P(refinement)) {
 | 
			
		||||
	    return refiend_method_original_method_entry(refinements, me, defined_class_ptr);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    tmp_me = method_entry_get(refinement, me->called_id, defined_class_ptr);
 | 
			
		||||
 | 
			
		||||
	    if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
		return tmp_me;
 | 
			
		||||
	    }
 | 
			
		||||
	    else {
 | 
			
		||||
		return refiend_method_original_method_entry(refinements, me, defined_class_ptr);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return me;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_method_entry_t *
 | 
			
		||||
rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    return resolve_refined_method(refinements, me, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_callable_method_entry_t *
 | 
			
		||||
rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me)
 | 
			
		||||
{
 | 
			
		||||
    VALUE defined_class = me->defined_class;
 | 
			
		||||
    const rb_method_entry_t *resolved_me = resolve_refined_method(refinements, (const rb_method_entry_t *)me, &defined_class);
 | 
			
		||||
 | 
			
		||||
    if (resolved_me && resolved_me->defined_class == 0) {
 | 
			
		||||
	return rb_method_entry_complement_defined_class(resolved_me, defined_class);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	return (const rb_callable_method_entry_t *)resolved_me;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
remove_method(VALUE klass, ID mid)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -889,7 +1014,7 @@ rb_export_method(VALUE klass, ID name, rb_method_visibility_t visi)
 | 
			
		|||
int
 | 
			
		||||
rb_method_boundp(VALUE klass, ID id, int ex)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry_without_refinements(klass, id, 0);
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry_without_refinements(klass, id);
 | 
			
		||||
 | 
			
		||||
    if (me != 0) {
 | 
			
		||||
	if ((ex & ~BOUND_RESPONDS) &&
 | 
			
		||||
| 
						 | 
				
			
			@ -1123,7 +1248,7 @@ check_definition(VALUE mod, VALUE mid, rb_method_visibility_t visi)
 | 
			
		|||
    const rb_method_entry_t *me;
 | 
			
		||||
    ID id = rb_check_id(&mid);
 | 
			
		||||
    if (!id) return Qfalse;
 | 
			
		||||
    me = rb_method_entry_without_refinements(mod, id, 0);
 | 
			
		||||
    me = rb_method_entry_without_refinements(mod, id);
 | 
			
		||||
    if (me) {
 | 
			
		||||
	if (METHOD_ENTRY_VISI(me) == visi) return Qtrue;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1354,7 +1479,7 @@ rb_alias(VALUE klass, ID alias_name, ID original_name)
 | 
			
		|||
  again:
 | 
			
		||||
    orig_me = search_method(klass, original_name, &defined_class);
 | 
			
		||||
    if (orig_me && orig_me->def->type == VM_METHOD_TYPE_REFINED) {
 | 
			
		||||
	orig_me = rb_resolve_refined_method(Qnil, orig_me, &defined_class);
 | 
			
		||||
	orig_me = rb_resolve_refined_method(Qnil, orig_me);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
 | 
			
		||||
| 
						 | 
				
			
			@ -1375,26 +1500,19 @@ rb_alias(VALUE klass, ID alias_name, ID original_name)
 | 
			
		|||
 | 
			
		||||
    if (visi == METHOD_VISI_UNDEF) visi = METHOD_ENTRY_VISI(orig_me);
 | 
			
		||||
 | 
			
		||||
    if (defined_class != target_klass) { /* inter class/module alias */
 | 
			
		||||
	VALUE real_owner;
 | 
			
		||||
    if (orig_me->defined_class == 0) {
 | 
			
		||||
	rb_method_entry_t *alias_me;
 | 
			
		||||
 | 
			
		||||
	if (RB_TYPE_P(defined_class, T_ICLASS)) {
 | 
			
		||||
	    defined_class = real_owner = RBASIC_CLASS(defined_class);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    real_owner = defined_class;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* make mthod entry */
 | 
			
		||||
	alias_me = rb_add_method(target_klass, alias_name, VM_METHOD_TYPE_ALIAS, rb_method_entry_clone(orig_me), visi);
 | 
			
		||||
	RB_OBJ_WRITE(alias_me, &alias_me->klass, defined_class);
 | 
			
		||||
	alias_me = rb_add_method(target_klass, alias_name, VM_METHOD_TYPE_ALIAS, (void *)rb_method_entry_clone(orig_me), visi);
 | 
			
		||||
	alias_me->def->original_id = orig_me->called_id;
 | 
			
		||||
	*(ID *)&alias_me->def->body.alias.original_me->called_id = alias_name;
 | 
			
		||||
	METHOD_ENTRY_SAFE_SET(alias_me, METHOD_ENTRY_SAFE(orig_me));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	method_entry_set(target_klass, alias_name, orig_me, visi, defined_class);
 | 
			
		||||
	rb_method_entry_t *alias_me;
 | 
			
		||||
 | 
			
		||||
	alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner);
 | 
			
		||||
	RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass);
 | 
			
		||||
	RB_OBJ_WRITE(alias_me, &alias_me->defined_class, defined_class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1690,7 +1808,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
 | 
			
		|||
int
 | 
			
		||||
rb_method_basic_definition_p(VALUE klass, ID id)
 | 
			
		||||
{
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(klass, id, 0);
 | 
			
		||||
    const rb_method_entry_t *me = rb_method_entry(klass, id);
 | 
			
		||||
    return (me && METHOD_ENTRY_BASIC(me)) ? TRUE : FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1876,7 +1994,7 @@ Init_eval_method(void)
 | 
			
		|||
 | 
			
		||||
    {
 | 
			
		||||
#define REPLICATE_METHOD(klass, id) do { \
 | 
			
		||||
	    const rb_method_entry_t *me = rb_method_entry((klass), (id), 0); \
 | 
			
		||||
	    const rb_method_entry_t *me = rb_method_entry((klass), (id)); \
 | 
			
		||||
	    rb_method_entry_set((klass), (id), me, METHOD_ENTRY_VISI(me)); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue