diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index f57bf62..550a1aa 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -287,16 +287,17 @@ assert_equal '1',       %q( class C; def m() 1 end end
 assert_equal '1',       %q( class C
                               def m
                                 def mm() 1 end
+                                mm
                               end
                             end
-                            C.new.m
-                            C.new.mm )
+                            C.new.m )
 assert_equal '1',       %q( class C
                               def m
                                 def mm() 1 end
+                                mm
                               end
                             end
-                            instance_eval "C.new.m; C.new.mm" )
+                            instance_eval "C.new.m" )
 
 # method_missing
 assert_equal ':m',      %q( class C
diff --git a/class.c b/class.c
index 9ad8ec8..2547238 100644
--- a/class.c
+++ b/class.c
@@ -594,8 +594,8 @@ rb_define_module_id_under(VALUE outer, ID id)
     return module;
 }
 
-static VALUE
-include_class_new(VALUE module, VALUE super)
+VALUE
+rb_include_class_new(VALUE module, VALUE super)
 {
     VALUE klass = class_alloc(T_ICLASS, rb_cClass);
 
@@ -658,7 +658,7 @@ rb_include_module(VALUE klass, VALUE module)
 		break;
 	    }
 	}
-	c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
+	c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
 	if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
 	    changed = 1;
       skip:
@@ -1360,7 +1360,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"));
+    const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"), 0);
     if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
 	me->def->body.cfunc.func == rb_any_to_s)
 	return 1;
diff --git a/compile.c b/compile.c
index 2fd804c..d56de76 100644
--- a/compile.c
+++ b/compile.c
@@ -4571,7 +4571,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
 	ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid));
 	ADD_INSN1(ret, nd_line(node), putiseq, iseqval);
-	ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(3));
+	ADD_INSN1(ret, nd_line(node), putobject,
+		  node->flags & NODE_FL_NESTED_DEF ? Qtrue : Qfalse);
+	ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(4));
 
 	if (poped) {
 	    ADD_INSN(ret, nd_line(node), pop);
diff --git a/eval.c b/eval.c
index 2596921..ba6a87d 100644
--- a/eval.c
+++ b/eval.c
@@ -20,9 +20,11 @@
 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
 
 VALUE proc_invoke(VALUE, VALUE, VALUE, VALUE);
-VALUE rb_binding_new(void);
+VALUE rb_binding_new(int);
 NORETURN(void rb_raise_jump(VALUE));
 
+NODE *rb_vm_get_cref(const rb_iseq_t *, const VALUE *, const VALUE *);
+
 ID rb_frame_callee(void);
 VALUE rb_eLocalJumpError;
 VALUE rb_eSysStackError;
@@ -968,6 +970,70 @@ top_include(int argc, VALUE *argv, VALUE self)
     return rb_mod_include(argc, argv, rb_cObject);
 }
 
+void
+rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
+{
+    VALUE iclass, c, superclass = klass;
+
+    Check_Type(module, T_MODULE);
+    if (NIL_P(cref->nd_omod)) {
+	cref->nd_omod = rb_hash_new();
+	rb_funcall(cref->nd_omod, rb_intern("compare_by_identity"), 0);
+    }
+    else {
+	if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
+	    cref->nd_omod = rb_hash_dup(cref->nd_omod);
+	    cref->flags &= ~NODE_FL_CREF_OMOD_SHARED;
+	}
+	if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
+	    superclass = c;
+	}
+    }
+    c = iclass = rb_include_class_new(module, superclass);
+    module = RCLASS_SUPER(module);
+    while (module) {
+	c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
+	module = RCLASS_SUPER(module);
+    }
+    rb_hash_aset(cref->nd_omod, klass, iclass);
+    rb_clear_cache_by_class(klass);
+}
+
+/*
+ *  call-seq:
+ *     overlay_module(klass, mod [, binding])
+ *
+ *  Append features of <i>mod</i> to <i>klass</i> only in the scope where
+ *  <code>overlay_module</code> is called.
+ */
+
+static VALUE
+f_overlay_module(int argc, VALUE *argv, VALUE self)
+{
+    VALUE klass, module, binding;
+    NODE *cref;
+
+    rb_scan_args(argc, argv, "21", &klass, &module, &binding);
+    if (NIL_P(binding)) {
+	cref = rb_vm_cref();
+    }
+    else {
+	rb_binding_t *bind;
+	rb_env_t *env;
+
+	if (!rb_obj_is_kind_of(binding, rb_cBinding)) {
+	    rb_raise(rb_eTypeError,
+		     "wrong argument type %s (expected Binding)",
+		     rb_obj_classname(binding));
+	}
+	GetBindingPtr(binding, bind);
+	GetEnvPtr(bind->env, env);
+	cref = rb_vm_get_cref(env->block.iseq, env->block.lfp, env->block.dfp);
+    }
+    rb_overlay_module(cref, klass, module);
+    return Qnil;
+}
+
 VALUE rb_f_trace_var();
 VALUE rb_f_untrace_var();
 
@@ -1135,6 +1201,8 @@ Init_eval(void)
 
     rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1);
 
+    rb_define_global_function("overlay_module", f_overlay_module, -1);
+
     rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
 
     rb_define_global_function("trace_var", rb_f_trace_var, -1);	/* in variable.c */
diff --git a/gc.c b/gc.c
index 9bde487..077331a 100644
--- a/gc.c
+++ b/gc.c
@@ -1696,6 +1696,12 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
 	    ptr = (VALUE)obj->as.node.u2.node;
 	    goto again;
 
+	  case NODE_CREF:
+	    gc_mark(objspace, obj->as.node.u0.value, lev);
+	    gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
+	    ptr = (VALUE)obj->as.node.u3.node;
+	    goto again;
+
 	  default:		/* unlisted NODE */
 	    if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
 		gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 0ae4d47..00c844a 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -169,6 +169,7 @@ VALUE rb_define_class_id_under(VALUE, ID, VALUE);
 VALUE rb_module_new(void);
 VALUE rb_define_module_id(ID);
 VALUE rb_define_module_id_under(VALUE, ID);
+VALUE rb_include_class_new(VALUE, VALUE);
 VALUE rb_mod_included_modules(VALUE);
 VALUE rb_mod_include_p(VALUE, VALUE);
 VALUE rb_mod_ancestors(VALUE);
@@ -321,7 +322,7 @@ VALUE rb_proc_call(VALUE, VALUE);
 VALUE rb_proc_call_with_block(VALUE, int argc, VALUE *argv, VALUE);
 int rb_proc_arity(VALUE);
 VALUE rb_proc_lambda_p(VALUE);
-VALUE rb_binding_new(void);
+VALUE rb_binding_new(int);
 VALUE rb_obj_method(VALUE, VALUE);
 VALUE rb_method_call(int, VALUE*, VALUE);
 int rb_mod_method_arity(VALUE, ID);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 028f4e9..30272ef 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -621,6 +621,7 @@ struct RClass {
 #define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
 #define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
 #define RMODULE_SUPER(m) RCLASS_SUPER(m)
+#define RMODULE_HAS_NESTED_METHODS FL_USER2
 
 struct RFloat {
     struct RBasic basic;
diff --git a/insns.def b/insns.def
index fcd97ae..8663ef3 100644
--- a/insns.def
+++ b/insns.def
@@ -183,7 +183,7 @@ getclassvariable
 ()
 (VALUE val)
 {
-    NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
+    NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
     val = rb_cvar_get(vm_get_cvar_base(cref), id);
 }
 
@@ -198,7 +198,7 @@ setclassvariable
 (VALUE val)
 ()
 {
-    NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
+    NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
     rb_cvar_set(vm_get_cvar_base(cref), id, val);
 }
 
@@ -788,7 +788,7 @@ defined
 	break;
       case DEFINED_METHOD:{
 	VALUE klass = CLASS_OF(v);
-	const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj));
+	const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0);
 
 	if (me) {
 	    if (!(me->flag & NOEX_PRIVATE)) {
@@ -960,7 +960,7 @@ defineclass
 
     /* enter scope */
     vm_push_frame(th, class_iseq,
-		  VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_BLOCK_PTR(),
+		  VM_FRAME_MAGIC_CLASS, klass, 0, (VALUE) GET_BLOCK_PTR(),
 		  class_iseq->iseq_encoded, GET_SP(), 0,
 		  class_iseq->local_size);
     RESTORE_REGS();
@@ -992,7 +992,7 @@ send
 (VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
 {
     const rb_method_entry_t *me;
-    VALUE recv, klass;
+    VALUE recv, klass, defined_class;
     rb_block_t *blockptr = 0;
     int num = caller_setup_args(th, GET_CFP(), op_flag, (int)op_argc,
 				(rb_iseq_t *)blockiseq, &blockptr);
@@ -1002,8 +1002,8 @@ send
     /* get receiver */
     recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
     klass = CLASS_OF(recv);
-    me = vm_method_search(id, klass, ic);
-    CALL_METHOD(num, blockptr, flag, id, me, recv);
+    me = vm_method_search(id, klass, ic, &defined_class);
+    CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class);
 }
 
 /**
@@ -1026,18 +1026,24 @@ invokesuper
     ID id;
     VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
     const rb_method_entry_t *me;
+    rb_iseq_t *ip;
 
     recv = GET_SELF();
     vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
 
-    /* temporary measure for [Bug #2402] [Bug #2502] [Bug #3136] */
-    if (!rb_obj_is_kind_of(recv, klass)) {
-	rb_raise(rb_eNotImpError, "super from singleton method that is defined to multiple classes is not supported; this will be fixed in 1.9.3 or later");
+    ip = GET_ISEQ();
+    while (ip && !ip->klass) {
+	ip = ip->parent_iseq;
+    }
+  again:
+    me = rb_method_entry(klass, id, &klass);
+    if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
+	me->def->body.iseq == ip) {
+	klass = RCLASS_SUPER(klass);
+	goto again;
     }
 
-    me = rb_method_entry(klass, id);
-
-    CALL_METHOD(num, blockptr, flag, id, me, recv);
+    CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
 }
 
 /**
@@ -1661,7 +1667,7 @@ opt_neq
 (VALUE val)
 {
     extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
-    const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic);
+    const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic, 0);
     val = Qundef;
 
     if (check_cfunc(me, rb_obj_not_equal)) {
@@ -2062,7 +2068,7 @@ opt_not
 (VALUE val)
 {
     extern VALUE rb_obj_not(VALUE obj);
-    const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic);
+    const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic, 0);
 
     if (check_cfunc(me, rb_obj_not)) {
 	val = RTEST(recv) ? Qfalse : Qtrue;
diff --git a/iseq.c b/iseq.c
index d7c8fb3..3f5cb1e 100644
--- a/iseq.c
+++ b/iseq.c
@@ -179,20 +179,20 @@ set_relation(rb_iseq_t *iseq, const VALUE parent)
     /* set class nest stack */
     if (type == ISEQ_TYPE_TOP) {
 	/* toplevel is private */
-	iseq->cref_stack = NEW_BLOCK(rb_cObject);
-	iseq->cref_stack->nd_file = 0;
+	iseq->cref_stack = NEW_CREF(rb_cObject);
+	iseq->cref_stack->nd_omod = Qnil;
 	iseq->cref_stack->nd_visi = NOEX_PRIVATE;
 	if (th->top_wrapper) {
-	    NODE *cref = NEW_BLOCK(th->top_wrapper);
-	    cref->nd_file = 0;
+	    NODE *cref = NEW_CREF(th->top_wrapper);
+	    cref->nd_omod = Qnil;
 	    cref->nd_visi = NOEX_PRIVATE;
 	    cref->nd_next = iseq->cref_stack;
 	    iseq->cref_stack = cref;
 	}
     }
     else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
-	iseq->cref_stack = NEW_BLOCK(0); /* place holder */
-	iseq->cref_stack->nd_file = 0;
+	iseq->cref_stack = NEW_CREF(0); /* place holder */
+	iseq->cref_stack->nd_omod = Qnil;
     }
     else if (RTEST(parent)) {
 	rb_iseq_t *piseq;
@@ -1365,7 +1365,9 @@ rb_iseq_clone(VALUE iseqval, VALUE newcbase)
 	iseq1->local_iseq = iseq1;
     }
     if (newcbase) {
-	iseq1->cref_stack = NEW_BLOCK(newcbase);
+	iseq1->cref_stack = NEW_CREF(newcbase);
+	iseq1->cref_stack->nd_omod = iseq0->cref_stack->nd_omod;
+	iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
 	if (iseq0->cref_stack->nd_next) {
 	    iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
 	}
diff --git a/lib/classbox.rb b/lib/classbox.rb
new file mode 100644
index 0000000..91e9ab9
--- /dev/null
+++ b/lib/classbox.rb
@@ -0,0 +1,47 @@
+class Classbox < Module
+  def import_to(binding)
+    @__overlayed_modules__.each do |klass, modules|
+      modules.each do |mod|
+        overlay_module(klass, mod, binding)
+      end
+    end
+  end
+
+  private
+
+  def initialize
+    super
+    @__overlayed_modules__ = {}
+  end
+
+  @@__optimized_methods__ = [
+    :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :>, :>=, :!, :!=,
+    :length, :size, :succ
+  ]
+
+  def refine(klass, &block)
+    mod = Module.new
+    modules = @__overlayed_modules__[klass] ||= []
+    modules.push(mod)
+    overlay_module(klass, mod, binding(1))
+    mod.singleton_class.send(:define_method, :method_added) do |mid|
+      if @@__optimized_methods__.include?(mid)
+        klass.send(:alias_method, :__original_optimized_method__, mid)
+        klass.send(:define_method, mid) {}
+        klass.send(:alias_method, mid, :__original_optimized_method__)
+        klass.send(:remove_method, :__original_optimized_method__)
+      end
+    end
+    mod.module_eval(&block)
+  end
+end
+
+def classbox(name, &block)
+  classbox = Classbox.new
+  Object.const_set(name, classbox)
+  classbox.module_eval(&block)
+end
+
+def import_classbox(classbox)
+  classbox.import_to(binding(1))
+end
diff --git a/method.h b/method.h
index e03f0d2..73ff8df 100644
--- a/method.h
+++ b/method.h
@@ -89,9 +89,9 @@ struct unlinked_method_entry_list_entry {
 
 void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
 rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
-rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
+rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
 
-rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id);
+rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *define_class_ptr);
 rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
 
 int rb_method_entry_arity(const rb_method_entry_t *me);
diff --git a/node.h b/node.h
index 82f7ba0..405a469 100644
--- a/node.h
+++ b/node.h
@@ -188,6 +188,8 @@ enum node_type {
 #define NODE_COLON2      NODE_COLON2
     NODE_COLON3,
 #define NODE_COLON3      NODE_COLON3
+    NODE_CREF,
+#define NODE_CREF        NODE_CREF
     NODE_DOT2,
 #define NODE_DOT2        NODE_DOT2
     NODE_DOT3,
@@ -234,7 +236,10 @@ enum node_type {
 
 typedef struct RNode {
     unsigned long flags;
-    char *nd_file;
+    union {
+	char *file;
+	VALUE value;
+    } u0;
     union {
 	struct RNode *node;
 	ID id;
@@ -260,9 +265,11 @@ typedef struct RNode {
 
 #define RNODE(obj)  (R_CAST(RNode)(obj))
 
-/* 0..4:T_TYPES, 5:FL_MARK, 6:reserved, 7:NODE_FL_NEWLINE */
+/* 0..4:T_TYPES, 5:FL_MARK, 6:NODE_FL_NESTED_DEF, 7:NODE_FL_NEWLINE */
 #define NODE_FL_NEWLINE (((VALUE)1)<<7)
+#define NODE_FL_NESTED_DEF (((VALUE)1)<<6)
 #define NODE_FL_CREF_PUSHED_BY_EVAL NODE_FL_NEWLINE
+#define NODE_FL_CREF_OMOD_SHARED NODE_FL_NESTED_DEF
 
 #define NODE_TYPESHIFT 8
 #define NODE_TYPEMASK  (((VALUE)0x7f)<<NODE_TYPESHIFT)
@@ -277,6 +284,9 @@ typedef struct RNode {
 #define nd_set_line(n,l) \
     RNODE(n)->flags=((RNODE(n)->flags&~(-1<<NODE_LSHIFT))|(((l)&NODE_LMASK)<<NODE_LSHIFT))
 
+#define nd_file  u0.file
+#define nd_omod  u0.value
+
 #define nd_head  u1.node
 #define nd_alen  u2.argc
 #define nd_next  u3.node
@@ -433,6 +443,7 @@ typedef struct RNode {
 #define NEW_MODULE(n,b) NEW_NODE(NODE_MODULE,n,NEW_SCOPE(0,b),0)
 #define NEW_COLON2(c,i) NEW_NODE(NODE_COLON2,c,i,0)
 #define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0)
+#define NEW_CREF(a) NEW_NODE(NODE_CREF,a,0,0)
 #define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0)
 #define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0)
 #define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0)
diff --git a/parse.y b/parse.y
index e085088..35768a3 100644
--- a/parse.y
+++ b/parse.y
@@ -2953,6 +2953,8 @@ primary		: literal
 			reduce_nodes(&body);
 			$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE);
 			nd_set_line($$, $<num>1);
+			if (in_def > 1 || in_single > 0)
+			    $$->flags |= NODE_FL_NESTED_DEF;
 		    /*%
 			$$ = dispatch3(def, $2, $4, $5);
 		    %*/
diff --git a/proc.c b/proc.c
index 0489dd9..de2ed3d 100644
--- a/proc.c
+++ b/proc.c
@@ -15,6 +15,7 @@
 struct METHOD {
     VALUE recv;
     VALUE rclass;
+    VALUE defined_class;
     ID id;
     rb_method_entry_t me;
 };
@@ -310,13 +311,21 @@ binding_clone(VALUE self)
 }
 
 VALUE
-rb_binding_new(void)
+rb_binding_new(int level)
 {
     rb_thread_t *th = GET_THREAD();
     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
     VALUE bindval = binding_alloc(rb_cBinding);
     rb_binding_t *bind;
+    int i;
 
+    if (level < 0) {
+	rb_raise(rb_eArgError, "level should not be negative: %d", level);
+    }
+    for (i = 0; i < level && cfp; i++) {
+	cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+	cfp = rb_vm_get_ruby_level_next_cfp(th, cfp);
+    }
     if (cfp == 0) {
 	rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");
     }
@@ -345,9 +354,16 @@ rb_binding_new(void)
  */
 
 static VALUE
-rb_f_binding(VALUE self)
+rb_f_binding(int argc, VALUE *argv, VALUE self)
 {
-    return rb_binding_new();
+    VALUE vlevel;
+    int level = 0;
+
+    rb_scan_args(argc, argv, "01", &vlevel);
+    if (!NIL_P(vlevel)) {
+	level = NUM2INT(vlevel);
+    }
+    return rb_binding_new(level);
 }
 
 /*
@@ -861,6 +877,7 @@ 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_mark_method_entry(&data->me);
@@ -903,7 +920,7 @@ static VALUE
 mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
 {
     VALUE method;
-    VALUE rclass = klass;
+    VALUE rclass = klass, defined_class;
     ID rid = id;
     struct METHOD *data;
     rb_method_entry_t *me, meb;
@@ -911,7 +928,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
     rb_method_flag_t flag = NOEX_UNDEF;
 
   again:
-    me = rb_method_entry(klass, id);
+    me = rb_method_entry(klass, id, &defined_class);
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	ID rmiss = rb_intern("respond_to_missing?");
 	VALUE sym = ID2SYM(id);
@@ -953,12 +970,12 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
 	}
     }
     if (def && def->type == VM_METHOD_TYPE_ZSUPER) {
-	klass = RCLASS_SUPER(me->klass);
+	klass = RCLASS_SUPER(defined_class);
 	id = def->original_id;
 	goto again;
     }
 
-    klass = me->klass;
+    klass = defined_class;
 
     while (rclass != klass &&
 	   (FL_TEST(rclass, FL_SINGLETON) || TYPE(rclass) == T_ICLASS)) {
@@ -974,6 +991,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
 
     data->recv = obj;
     data->rclass = rclass;
+    data->defined_class = defined_class;
     data->id = rid;
     data->me = *me;
     if (def) def->alias_count++;
@@ -1085,6 +1103,7 @@ method_unbind(VALUE obj)
     data->me = orig->me;
     if (orig->me.def) orig->me.def->alias_count++;
     data->rclass = orig->rclass;
+    data->defined_class = orig->defined_class;
     OBJ_INFECT(method, obj);
 
     return method;
@@ -1421,10 +1440,10 @@ rb_method_call(int argc, VALUE *argv, VALUE method)
     if ((state = EXEC_TAG()) == 0) {
 	rb_thread_t *th = GET_THREAD();
 	VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
-			 const rb_method_entry_t *me);
+			 const rb_method_entry_t *me, VALUE defined_class);
 
 	PASS_PASSED_BLOCK_TH(th);
-	result = rb_vm_call(th, data->recv, data->id,  argc, argv, &data->me);
+	result = rb_vm_call(th, data->recv, data->id,  argc, argv, &data->me, data->defined_class);
     }
     POP_TAG();
     if (safe >= 0)
@@ -1648,7 +1667,7 @@ method_arity(VALUE method)
 int
 rb_mod_method_arity(VALUE mod, ID id)
 {
-    rb_method_entry_t *me = rb_method_entry(mod, id);
+    rb_method_entry_t *me = rb_method_entry(mod, id, 0);
     return rb_method_entry_arity(me);
 }
 
@@ -2234,6 +2253,6 @@ Init_Binding(void)
     rb_define_method(rb_cBinding, "clone", binding_clone, 0);
     rb_define_method(rb_cBinding, "dup", binding_dup, 0);
     rb_define_method(rb_cBinding, "eval", bind_eval, -1);
-    rb_define_global_function("binding", rb_f_binding, 0);
+    rb_define_global_function("binding", rb_f_binding, -1);
 }
 
diff --git a/test/rdoc/test_rdoc_text.rb b/test/rdoc/test_rdoc_text.rb
index 7e0f2cf..3b4b78e 100644
--- a/test/rdoc/test_rdoc_text.rb
+++ b/test/rdoc/test_rdoc_text.rb
@@ -62,8 +62,8 @@ The comments associated with
     assert_equal expected, flush_left(text)
   end
 
+  def formatter() RDoc::Markup::ToHtml.new end
   def test_markup
-    def formatter() RDoc::Markup::ToHtml.new end
 
     assert_equal "<p>\nhi\n</p>\n", markup('hi')
   end
diff --git a/thread.c b/thread.c
index 6c783c9..55e6030 100644
--- a/thread.c
+++ b/thread.c
@@ -4074,7 +4074,7 @@ call_trace_proc(VALUE args, int tracing)
     argv[1] = filename;
     argv[2] = INT2FIX(line);
     argv[3] = id ? ID2SYM(id) : Qnil;
-    argv[4] = (p->self && srcfile) ? rb_binding_new() : Qnil;
+    argv[4] = (p->self && srcfile) ? rb_binding_new(0) : Qnil;
     argv[5] = klass ? klass : Qnil;
 
     return rb_proc_call_with_block(p->proc, 6, argv, Qnil);
diff --git a/vm.c b/vm.c
index 558e980..949fdb6 100644
--- a/vm.c
+++ b/vm.c
@@ -69,7 +69,7 @@ static inline VALUE
 rb_vm_set_finish_env(rb_thread_t * th)
 {
     vm_push_frame(th, 0, VM_FRAME_MAGIC_FINISH,
-		  Qnil, th->cfp->lfp[0], 0,
+		  Qnil, Qnil, th->cfp->lfp[0], 0,
 		  th->cfp->sp, 0, 1);
     th->cfp->pc = (VALUE *)&finish_insn_seq[0];
     return Qtrue;
@@ -89,7 +89,7 @@ vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
     rb_vm_set_finish_env(th);
 
     vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP,
-		  th->top_self, 0, iseq->iseq_encoded,
+		  th->top_self, rb_cObject, 0, iseq->iseq_encoded,
 		  th->cfp->sp, 0, iseq->local_size);
 
     CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
@@ -104,7 +104,7 @@ vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref)
 
     /* for return */
     rb_vm_set_finish_env(th);
-    vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self,
+    vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self, block->klass,
 		  GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded,
 		  th->cfp->sp, block->lfp, iseq->local_size);
 
@@ -495,6 +495,7 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
     GetProcPtr(procval, proc);
     proc->blockprocval = blockprocval;
     proc->block.self = block->self;
+    proc->block.klass = block->klass;
     proc->block.lfp = block->lfp;
     proc->block.dfp = block->dfp;
     proc->block.iseq = block->iseq;
@@ -544,9 +545,11 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 				     type == VM_FRAME_MAGIC_LAMBDA);
 
 	ncfp = vm_push_frame(th, iseq, type,
-			     self, GC_GUARDED_PTR(block->dfp),
+			     self, th->passed_defined_class,
+			     GC_GUARDED_PTR(block->dfp),
 			     iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp,
 			     iseq->local_size - arg_size);
+	th->passed_defined_class = 0;
 	ncfp->me = th->passed_me;
 	th->passed_me = 0;
 
@@ -819,7 +822,8 @@ rb_vm_cref(void)
 {
     rb_thread_t *th = GET_THREAD();
     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
-    return vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
+    if (!cfp) return NULL;
+    return rb_vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
 }
 
 #if 0
@@ -1320,7 +1324,8 @@ vm_exec(rb_thread_t *th)
 	    /* push block frame */
 	    cfp->sp[0] = err;
 	    vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
-			  cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded,
+			  cfp->self, cfp->klass,
+			  (VALUE)cfp->dfp, catch_iseq->iseq_encoded,
 			  cfp->sp + 1 /* push value */, cfp->lfp, catch_iseq->local_size - 1);
 
 	    state = 0;
@@ -1458,7 +1463,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,
-		  recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
+		  recv, CLASS_OF(recv), (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
 
     val = (*func)(arg);
 
@@ -1671,6 +1676,7 @@ rb_thread_mark(void *ptr)
 	RUBY_MARK_UNLESS_NULL(th->root_fiber);
 	RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
 	RUBY_MARK_UNLESS_NULL(th->last_status);
+	RUBY_MARK_UNLESS_NULL(th->passed_defined_class);
 
 	RUBY_MARK_UNLESS_NULL(th->locking_mutex);
 
@@ -1794,7 +1800,7 @@ th_init2(rb_thread_t *th, VALUE self)
 
     th->cfp = (void *)(th->stack + th->stack_size);
 
-    vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, 0, 0,
+    vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, Qnil, 0, 0,
 		  th->stack, 0, 1);
 
     th->status = THREAD_RUNNABLE;
@@ -1835,14 +1841,37 @@ rb_thread_alloc(VALUE klass)
     return self;
 }
 
+static VALUE
+find_module_for_nested_methods(NODE *cref, VALUE klass)
+{
+    VALUE iclass;
+
+    if (NIL_P(cref->nd_omod))
+	return Qnil;
+    iclass = rb_hash_lookup(cref->nd_omod, klass);
+    if (NIL_P(iclass))
+	return Qnil;
+    while (iclass) {
+	VALUE module = RBASIC(iclass)->klass;
+	if (FL_TEST(module, RMODULE_HAS_NESTED_METHODS)) {
+	    return module;
+	}
+	iclass = RCLASS_SUPER(iclass);
+    }
+    return Qnil;
+}
+
 VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
 
 static void
-vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
+vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, VALUE nested,
 		 rb_num_t is_singleton, NODE *cref)
 {
     VALUE klass = cref->nd_clss;
+    VALUE target, defined_class;
+    rb_method_entry_t *me;
     int noex = (int)cref->nd_visi;
+    int is_nested = RTEST(nested);
     rb_iseq_t *miseq;
     GetISeqPtr(iseqval, miseq);
 
@@ -1870,11 +1899,30 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
 	noex = NOEX_PUBLIC;
     }
 
+    if (is_nested && th->cfp->lfp == th->cfp->dfp) {
+	target = find_module_for_nested_methods(cref, klass);
+	if (NIL_P(target)) {
+	    target = rb_module_new();
+	    FL_SET(target, RMODULE_HAS_NESTED_METHODS);
+	    rb_overlay_module(cref, klass, target);
+	}
+	else {
+	    me = search_method(target, id, Qnil, &defined_class);
+	    if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
+		me->def->body.iseq == miseq) {
+		return;
+	    }
+	}
+	noex = NOEX_PRIVATE;
+    }
+    else {
+	target = klass;
+    }
     /* dup */
     COPY_CREF(miseq->cref_stack, cref);
-    miseq->klass = klass;
+    miseq->klass = target;
     miseq->defined_method_id = id;
-    rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
+    rb_add_method(target, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
 
     if (!is_singleton && noex == NOEX_MODFUNC) {
 	rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
@@ -1888,10 +1936,10 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
 } while (0)
 
 static VALUE
-m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
+m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval, VALUE nested)
 {
     REWIND_CFP({
-	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref());
+	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, nested, 0, rb_vm_cref());
     });
     return Qnil;
 }
@@ -1900,7 +1948,7 @@ static VALUE
 m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
 {
     REWIND_CFP({
-	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref());
+	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, Qfalse, 1, rb_vm_cref());
     });
     return Qnil;
 }
@@ -2016,7 +2064,7 @@ Init_VM(void)
     rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
     rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
     rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
-    rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3);
+    rb_define_method_id(klass, id_core_define_method, m_core_define_method, 4);
     rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3);
     rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1);
     rb_obj_freeze(fcore);
@@ -2108,7 +2156,7 @@ Init_VM(void)
 	th->cfp->pc = iseq->iseq_encoded;
 	th->cfp->self = th->top_self;
 
-	rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
+	rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new(0));
     }
     vm_init_redefined_flag();
 }
diff --git a/vm_core.h b/vm_core.h
index 7676b2f..2ef3ff5 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -142,6 +142,9 @@ struct iseq_inline_cache_entry {
 	rb_method_entry_t *method;
 	long index;
     } ic_value;
+    union {
+	VALUE defined_class;
+    } ic_value2;
 };
 
 #if 1
@@ -324,16 +327,18 @@ typedef struct {
     VALUE *bp;			/* cfp[2] */
     rb_iseq_t *iseq;		/* cfp[3] */
     VALUE flag;			/* cfp[4] */
-    VALUE self;			/* cfp[5] / block[0] */
-    VALUE *lfp;			/* cfp[6] / block[1] */
-    VALUE *dfp;			/* cfp[7] / block[2] */
-    rb_iseq_t *block_iseq;	/* cfp[8] / block[3] */
-    VALUE proc;			/* cfp[9] / block[4] */
-    const rb_method_entry_t *me;/* cfp[10] */
+    VALUE self;			/* cfp[5]  / block[0] */
+    VALUE klass;		/* cfp[6]  / block[1] */
+    VALUE *lfp;			/* cfp[7]  / block[2] */
+    VALUE *dfp;			/* cfp[8]  / block[3] */
+    rb_iseq_t *block_iseq;	/* cfp[9]  / block[4] */
+    VALUE proc;			/* cfp[10] / block[5] */
+    const rb_method_entry_t *me;/* cfp[11] */
 } rb_control_frame_t;
 
 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 *lfp;			/* share with method frame if it's only block */
     VALUE *dfp;			/* share with method frame if it's only block */
     rb_iseq_t *iseq;
@@ -395,6 +400,7 @@ typedef struct rb_thread_struct
 
     /* for bmethod */
     const rb_method_entry_t *passed_me;
+    VALUE passed_defined_class;
 
     /* for load(true) */
     VALUE top_self;
@@ -697,6 +703,8 @@ rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self,
     } \
 } while (0)
 
+void rb_overlay_module(NODE*, VALUE, VALUE);
+
 #if defined __GNUC__ && __GNUC__ >= 4
 #pragma GCC visibility push(default)
 #endif
diff --git a/vm_eval.c b/vm_eval.c
index ca3fbba..374a999 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -33,11 +33,11 @@ static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type sc
 
 static inline VALUE
 vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
-	 const rb_method_entry_t *me)
+	 const rb_method_entry_t *me, VALUE defined_class)
 {
     const rb_method_definition_t *def = me->def;
     VALUE val;
-    VALUE klass = me->klass;
+    VALUE klass = defined_class;
     const rb_block_t *blockptr = 0;
 
     if (!def) return Qnil;
@@ -62,7 +62,7 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
 	    *reg_cfp->sp++ = argv[i];
 	}
 
-	vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me);
+	vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me, klass);
 	val = vm_exec(th);
 	break;
       }
@@ -73,7 +73,7 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
 	    rb_control_frame_t *reg_cfp = th->cfp;
 	    rb_control_frame_t *cfp =
 		vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
-			      recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
+			      recv, klass, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
 
 	    cfp->me = me;
 	    val = call_cfunc(def->body.cfunc.func, recv, def->body.cfunc.argc, argc, argv);
@@ -101,12 +101,12 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
 	break;
       }
       case VM_METHOD_TYPE_BMETHOD: {
-	val = vm_call_bmethod(th, recv, argc, argv, blockptr, me);
+	val = vm_call_bmethod(th, recv, argc, argv, blockptr, me, klass);
 	break;
       }
       case VM_METHOD_TYPE_ZSUPER: {
 	klass = RCLASS_SUPER(klass);
-	if (!klass || !(me = rb_method_entry(klass, id))) {
+	if (!klass || !(me = rb_method_entry(klass, id, &klass))) {
 	    return method_missing(recv, id, argc, argv, NOEX_SUPER);
 	}
 	RUBY_VM_CHECK_INTS();
@@ -149,9 +149,9 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, 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)
+	   const rb_method_entry_t *me, VALUE defined_class)
 {
-    return vm_call0(th, recv, id, argc, argv, me);
+    return vm_call0(th, recv, id, argc, argv, me, defined_class);
 }
 
 static inline VALUE
@@ -163,9 +163,8 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
     rb_method_entry_t *me;
     rb_control_frame_t *cfp = th->cfp;
 
-    if (!cfp->iseq) {
-	klass = cfp->me->klass;
-	klass = RCLASS_SUPER(klass);
+    if (!cfp->iseq && !NIL_P(cfp->klass)) {
+	klass = RCLASS_SUPER(cfp->klass);
 
 	if (klass == 0) {
 	    klass = vm_search_normal_superclass(cfp->me->klass, recv);
@@ -176,12 +175,12 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
 	rb_bug("vm_call_super: should not be reached");
     }
 
-    me = rb_method_entry(klass, id);
+    me = rb_method_entry(klass, id, &klass);
     if (!me) {
 	return method_missing(recv, id, argc, argv, NOEX_SUPER);
     }
 
-    return vm_call0(th, recv, id, argc, argv, me);
+    return vm_call0(th, recv, id, argc, argv, me, klass);
 }
 
 VALUE
@@ -202,7 +201,7 @@ stack_check(void)
     }
 }
 
-static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid);
+static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
 static inline int rb_method_call_status(rb_thread_t *th, rb_method_entry_t *me, call_type scope, VALUE self);
 #define NOEX_OK NOEX_NOSUPER
 
@@ -224,7 +223,8 @@ static inline VALUE
 rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
 	 call_type scope, VALUE self)
 {
-    rb_method_entry_t *me = rb_search_method_entry(recv, mid);
+    VALUE defined_class;
+    rb_method_entry_t *me = rb_search_method_entry(recv, mid, &defined_class);
     rb_thread_t *th = GET_THREAD();
     int call_status = rb_method_call_status(th, me, scope, self);
 
@@ -232,7 +232,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);
+    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 }
 
 struct rescue_funcall_args {
@@ -265,7 +265,8 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e)
 static VALUE
 check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
 {
-    rb_method_entry_t *me = rb_search_method_entry(recv, mid);
+    VALUE defined_class;
+    rb_method_entry_t *me = rb_search_method_entry(recv, mid, &defined_class);
     rb_thread_t *th = GET_THREAD();
     int call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
 
@@ -287,7 +288,7 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
 	}
     }
     stack_check();
-    return vm_call0(th, recv, mid, argc, argv, me);
+    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 }
 
 VALUE
@@ -332,7 +333,7 @@ rb_type_str(enum ruby_value_type type)
 }
 
 static inline rb_method_entry_t *
-rb_search_method_entry(VALUE recv, ID mid)
+rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
 {
     VALUE klass = CLASS_OF(recv);
 
@@ -371,7 +372,7 @@ rb_search_method_entry(VALUE recv, ID mid)
                          rb_id2name(mid), type, (void *)recv, flags, klass);
         }
     }
-    return rb_method_entry(klass, mid);
+    return rb_method_entry(klass, mid, defined_class_ptr);
 }
 
 static inline int
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 985a2fb..4bdf94c 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -22,7 +22,7 @@ static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_cont
 
 static inline rb_control_frame_t *
 vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq,
-	      VALUE type, VALUE self, VALUE specval,
+	      VALUE type, VALUE self, VALUE klass, VALUE specval,
 	      const VALUE *pc, VALUE *sp, VALUE *lfp,
 	      int local_size)
 {
@@ -61,6 +61,18 @@ vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq,
     cfp->block_iseq = 0;
     cfp->proc = 0;
     cfp->me = 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;
+	}
+    }
 
 #define COLLECT_PROFILE 0
 #if COLLECT_PROFILE
@@ -386,7 +398,7 @@ call_cfunc(VALUE (*func)(), VALUE recv,
 static inline VALUE
 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
 	      int num, VALUE recv, const rb_block_t *blockptr,
-	      const rb_method_entry_t *me)
+	      const rb_method_entry_t *me, VALUE defined_class)
 {
     VALUE val = 0;
     const rb_method_definition_t *def = me->def;
@@ -395,7 +407,8 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
     EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
 
     cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
-			recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
+			recv, defined_class, (VALUE) blockptr,
+		       	0, reg_cfp->sp, 0, 1);
     cfp->me = me;
     reg_cfp->sp -= num + 1;
 
@@ -414,13 +427,15 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
 
 static inline VALUE
 vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
-		const rb_block_t *blockptr, const rb_method_entry_t *me)
+		const rb_block_t *blockptr, const rb_method_entry_t *me,
+		VALUE defined_class)
 {
     rb_proc_t *proc;
     VALUE val;
 
     /* control block frame */
     th->passed_me = me;
+    th->passed_defined_class = defined_class;
 
     GetProcPtr(me->def->body.proc, proc);
     val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
@@ -451,7 +466,7 @@ vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
 static inline void
 vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
 		VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag,
-		const rb_method_entry_t *me)
+		const rb_method_entry_t *me, VALUE defined_class)
 {
     int opt_pc, i;
     VALUE *sp, *rsp = cfp->sp - argc;
@@ -474,7 +489,8 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
 	}
 
 	vm_push_frame(th, iseq,
-		      VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
+		      VM_FRAME_MAGIC_METHOD, recv, defined_class,
+		      (VALUE) blockptr,
 		      iseq->iseq_encoded + opt_pc, sp, 0, 0);
 
 	cfp->sp = rsp - 1 /* recv */;
@@ -497,7 +513,8 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
 	}
 
 	vm_push_frame(th, iseq,
-		      VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
+		      VM_FRAME_MAGIC_METHOD, recv, defined_class,
+		      (VALUE) blockptr,
 		      iseq->iseq_encoded + opt_pc, sp, 0, 0);
     }
 }
@@ -505,7 +522,8 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
 static inline VALUE
 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
 	       int num, const rb_block_t *blockptr, VALUE flag,
-	       ID id, const rb_method_entry_t *me, VALUE recv)
+	       ID id, const rb_method_entry_t *me,
+	       VALUE recv, VALUE defined_class)
 {
     VALUE val;
 
@@ -516,12 +534,14 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
 	  normal_method_dispatch:
 	    switch (me->def->type) {
 	      case VM_METHOD_TYPE_ISEQ:{
-		vm_setup_method(th, cfp, recv, num, blockptr, flag, me);
+		vm_setup_method(th, cfp, recv, num, blockptr, flag, me,
+			       	defined_class);
 		return Qundef;
 	      }
 	      case VM_METHOD_TYPE_NOTIMPLEMENTED:
 	      case VM_METHOD_TYPE_CFUNC:{
-		val = vm_call_cfunc(th, cfp, num, recv, blockptr, me);
+		val = vm_call_cfunc(th, cfp, num, recv, blockptr, me,
+				    defined_class);
 		break;
 	      }
 	      case VM_METHOD_TYPE_ATTRSET:{
@@ -552,12 +572,13 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
 		VALUE *argv = ALLOCA_N(VALUE, num);
 		MEMCPY(argv, cfp->sp - num, VALUE, num);
 		cfp->sp += - num - 1;
-		val = vm_call_bmethod(th, recv, num, argv, blockptr, me);
+		val = vm_call_bmethod(th, recv, num, argv, blockptr, me,
+				      defined_class);
 		break;
 	      }
 	      case VM_METHOD_TYPE_ZSUPER:{
 		VALUE klass = RCLASS_SUPER(me->klass);
-		me = rb_method_entry(klass, id);
+		me = rb_method_entry(klass, id, &defined_class);
 
 		if (me != 0) {
 		    goto normal_method_dispatch;
@@ -583,7 +604,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
 		    if (i > 0) {
 			MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
 		    }
-		    me = rb_method_entry(CLASS_OF(recv), id);
+		    me = rb_method_entry(CLASS_OF(recv), id, &defined_class);
 		    num -= 1;
 		    DEC_SP(1);
 		    flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT;
@@ -626,8 +647,6 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
 		val = vm_method_missing(th, id, recv, num, blockptr, stat);
 	    }
 	    else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) {
-		VALUE defined_class = me->klass;
-
 		if (TYPE(defined_class) == T_ICLASS) {
 		    defined_class = RBASIC(defined_class)->klass;
 		}
@@ -719,7 +738,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, (VALUE)block->dfp,
+		  self, 0, (VALUE)block->dfp,
 		  0, th->cfp->sp, block->lfp, 1);
 
     val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg);
@@ -934,7 +953,8 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_n
 				     block_proc_is_lambda(block->proc));
 
 	vm_push_frame(th, iseq,
-		      VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
+		      VM_FRAME_MAGIC_BLOCK, block->self, block->klass,
+		      (VALUE) block->dfp,
 		      iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp,
 		      iseq->local_size - arg_size);
 
@@ -1052,8 +1072,8 @@ vm_getspecial(rb_thread_t *th, VALUE *lfp, VALUE key, rb_num_t type)
     return val;
 }
 
-static NODE *
-vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
+NODE *
+rb_vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
 {
     NODE *cref = 0;
 
@@ -1070,7 +1090,7 @@ vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
     }
 
     if (cref == 0) {
-	rb_bug("vm_get_cref: unreachable");
+	rb_bug("rb_vm_get_cref: unreachable");
     }
     return cref;
 }
@@ -1079,15 +1099,20 @@ static NODE *
 vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
 {
     rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
-    NODE *cref = NEW_BLOCK(klass);
-    cref->nd_file = 0;
+    NODE *cref = NEW_CREF(klass);
+    cref->nd_omod = Qnil;
     cref->nd_visi = noex;
 
     if (blockptr) {
-	cref->nd_next = vm_get_cref(blockptr->iseq, blockptr->lfp, blockptr->dfp);
+	cref->nd_next = rb_vm_get_cref(blockptr->iseq, blockptr->lfp, blockptr->dfp);
     }
     else if (cfp) {
-	cref->nd_next = vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
+	cref->nd_next = rb_vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
+    }
+    /* TODO: why cref->nd_next is 1? */
+    if (cref->nd_next && cref->nd_next != (void *) 1 &&
+	!NIL_P(cref->nd_next->nd_omod)) {
+	COPY_CREF_OMOD(cref, cref->nd_next);
     }
 
     return cref;
@@ -1096,7 +1121,7 @@ vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
 static inline VALUE
 vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
 {
-    NODE *cref = vm_get_cref(iseq, lfp, dfp);
+    NODE *cref = rb_vm_get_cref(iseq, lfp, dfp);
     VALUE klass = Qundef;
 
     while (cref) {
@@ -1112,7 +1137,7 @@ vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
 static inline VALUE
 vm_get_const_base(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
 {
-    NODE *cref = vm_get_cref(iseq, lfp, dfp);
+    NODE *cref = rb_vm_get_cref(iseq, lfp, dfp);
     VALUE klass = Qundef;
 
     while (cref) {
@@ -1147,7 +1172,7 @@ vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
 
     if (orig_klass == Qnil) {
 	/* in current lexical scope */
-	const NODE *cref = vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp);
+	const NODE *cref = rb_vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp);
 	const NODE *root_cref = NULL;
 	VALUE klass = orig_klass;
 
@@ -1325,22 +1350,28 @@ vm_setivar(VALUE obj, ID id, VALUE val, IC ic)
 }
 
 static inline const rb_method_entry_t *
-vm_method_search(VALUE id, VALUE klass, IC ic)
+vm_method_search(VALUE id, VALUE klass, IC ic, VALUE *defined_class_ptr)
 {
     rb_method_entry_t *me;
 #if OPT_INLINE_METHOD_CACHE
     if (LIKELY(klass == ic->ic_class) &&
 	LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
 	me = ic->ic_value.method;
+	if (defined_class_ptr)
+	    *defined_class_ptr = ic->ic_value2.defined_class;
     }
     else {
-	me = rb_method_entry(klass, id);
+	VALUE defined_class;
+	me = rb_method_entry(klass, id, &defined_class);
+	if (defined_class_ptr)
+	    *defined_class_ptr = defined_class;
 	ic->ic_class = klass;
 	ic->ic_value.method = me;
+	ic->ic_value2.defined_class = defined_class;
 	ic->ic_vmstat = GET_VM_STATE_VERSION();
     }
 #else
-    me = rb_method_entry(klass, id);
+    me = rb_method_entry(klass, id, defined_class_ptr);
 #endif
     return me;
 }
@@ -1348,7 +1379,7 @@ vm_method_search(VALUE id, VALUE klass, IC ic)
 static inline VALUE
 vm_search_normal_superclass(VALUE klass, VALUE recv)
 {
-    if (BUILTIN_TYPE(klass) == T_CLASS) {
+    if (BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_ICLASS) {
 	return RCLASS_SUPER(klass);
     }
     else if (BUILTIN_TYPE(klass) == T_MODULE) {
@@ -1409,10 +1440,10 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip,
 	}
 
 	id = lcfp->me->def->original_id;
-	klass = vm_search_normal_superclass(lcfp->me->klass, recv);
+	klass = vm_search_normal_superclass(lcfp->klass, recv);
     }
     else {
-	klass = vm_search_normal_superclass(ip->klass, recv);
+	klass = vm_search_normal_superclass(reg_cfp->klass, recv);
     }
 
     *idp = id;
@@ -1682,7 +1713,7 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic)
     }
 
     {
-	const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic);
+	const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic, 0);
 	extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
 
 	if (check_cfunc(me, rb_obj_equal)) {
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 095b417..ad3f129 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -149,15 +149,24 @@ extern VALUE ruby_vm_const_missing_count;
 /* deal with control flow 2: method/iterator              */
 /**********************************************************/
 
+#define COPY_CREF_OMOD(c1, c2) do {  \
+  c1->nd_omod = c2->nd_omod; \
+  if (!NIL_P(c2->nd_omod)) { \
+      c1->flags |= NODE_FL_CREF_OMOD_SHARED; \
+      c2->flags |= NODE_FL_CREF_OMOD_SHARED; \
+  } \
+} while (0)
+
 #define COPY_CREF(c1, c2) do {  \
   NODE *__tmp_c2 = (c2); \
+  COPY_CREF_OMOD(c1, __tmp_c2); \
   c1->nd_clss = __tmp_c2->nd_clss; \
   c1->nd_visi = __tmp_c2->nd_visi;\
   c1->nd_next = __tmp_c2->nd_next; \
 } while (0)
 
-#define CALL_METHOD(num, blockptr, flag, id, me, recv) do { \
-    VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, me, recv); \
+#define CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class) do { \
+    VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, me, recv, defined_class); \
     if (v == Qundef) { \
 	RESTORE_REGS(); \
 	NEXT_INSN(); \
@@ -192,8 +201,9 @@ extern VALUE ruby_vm_const_missing_count;
 #if USE_IC_FOR_SPECIALIZED_METHOD
 
 #define CALL_SIMPLE_METHOD(num, id, recv) do { \
-    VALUE klass = CLASS_OF(recv); \
-    CALL_METHOD(num, 0, 0, id, vm_method_search(id, klass, ic), recv); \
+    VALUE klass = CLASS_OF(recv), defined_class; \
+    const rb_method_entry_t *me = vm_method_search(id, klass, ic, &defined_class); \
+    CALL_METHOD(num, 0, 0, id, me, recv, defined_class); \
 } while (0)
 
 #else
diff --git a/vm_method.c b/vm_method.c
index 50f0b12..2510a7d 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -4,7 +4,7 @@
 
 #define CACHE_SIZE 0x800
 #define CACHE_MASK 0x7ff
-#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
+#define EXPR1(c,o,m) ((((c)>>3)^((o)>>3)^(m))&CACHE_MASK)
 
 static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me);
 
@@ -15,7 +15,9 @@ static ID added, singleton_added, attached;
 struct cache_entry {		/* method hash table. */
     ID mid;			/* method's id */
     VALUE klass;		/* receiver's class */
+    VALUE omod;			/* overlay modules */
     rb_method_entry_t *me;
+    VALUE defined_class;
 };
 
 static struct cache_entry cache[CACHE_SIZE];
@@ -380,7 +382,7 @@ rb_get_alloc_func(VALUE klass)
 {
     rb_method_entry_t *me;
     Check_Type(klass, T_CLASS);
-    me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR);
+    me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR, 0);
 
     if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
 	return (rb_alloc_func_t)me->def->body.cfunc.func;
@@ -391,20 +393,32 @@ rb_get_alloc_func(VALUE klass)
 }
 
 static rb_method_entry_t*
-search_method(VALUE klass, ID id)
+search_method(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr)
 {
     st_data_t body;
+    VALUE iclass, skipped_class = Qnil;
+
     if (!klass) {
 	return 0;
     }
 
+    if (!NIL_P(omod) && !NIL_P(iclass = rb_hash_lookup(omod, klass))) {
+	klass = iclass;
+    }
     while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
 	klass = RCLASS_SUPER(klass);
+	if (!NIL_P(omod) && klass != skipped_class &&
+	    !NIL_P(iclass = rb_hash_lookup(omod, klass))) {
+	    skipped_class = klass;
+	    klass = iclass;
+	}
 	if (!klass) {
 	    return 0;
 	}
     }
 
+    if (defined_class_ptr)
+	*defined_class_ptr = klass;
     return (rb_method_entry_t *)body;
 }
 
@@ -415,14 +429,19 @@ search_method(VALUE klass, ID id)
  * rb_method_entry() simply.
  */
 rb_method_entry_t *
-rb_method_entry_get_without_cache(VALUE klass, ID id)
+rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *defined_class_ptr)
 {
-    rb_method_entry_t *me = search_method(klass, id);
+    VALUE iclass, defined_class;
+    rb_method_entry_t *me;
+
+    me = search_method(klass, id, omod, &defined_class);
 
     if (ruby_running) {
 	struct cache_entry *ent;
-	ent = cache + EXPR1(klass, id);
+	ent = cache + EXPR1(klass, omod, id);
 	ent->klass = klass;
+	ent->omod = omod;
+	ent->defined_class = defined_class;
 
 	if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	    ent->mid = id;
@@ -435,20 +454,31 @@ rb_method_entry_get_without_cache(VALUE klass, ID id)
 	}
     }
 
+    if (defined_class_ptr)
+	*defined_class_ptr = defined_class;
     return me;
 }
 
 rb_method_entry_t *
-rb_method_entry(VALUE klass, ID id)
+rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
     struct cache_entry *ent;
+    NODE *cref = rb_vm_cref();
+    VALUE omod = Qnil;
+
+    if (cref && !NIL_P(cref->nd_omod)) {
+	omod = cref->nd_omod;
+    }
 
-    ent = cache + EXPR1(klass, id);
-    if (ent->mid == id && ent->klass == klass) {
+    ent = cache + EXPR1(klass, omod, id);
+    if (ent->mid == id && ent->klass == klass && ent->omod == omod) {
+	if (defined_class_ptr)
+	    *defined_class_ptr = ent->defined_class;
 	return ent->me;
     }
 
-    return rb_method_entry_get_without_cache(klass, id);
+    return rb_method_entry_get_without_cache(klass, omod, id,
+					     defined_class_ptr);
 }
 
 static void
@@ -534,14 +564,15 @@ static void
 rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
 {
     rb_method_entry_t *me;
+    VALUE defined_class;
 
     if (klass == rb_cObject) {
 	rb_secure(4);
     }
 
-    me = search_method(klass, name);
+    me = search_method(klass, name, Qnil, &defined_class);
     if (!me && TYPE(klass) == T_MODULE) {
-	me = search_method(rb_cObject, name);
+	me = search_method(rb_cObject, name, Qnil, &defined_class);
     }
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -551,7 +582,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
     if (me->flag != noex) {
 	rb_vm_check_redefinition_opt_method(me);
 
-	if (klass == me->klass) {
+	if (klass == defined_class) {
 	    me->flag = noex;
 	}
 	else {
@@ -563,7 +594,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
 int
 rb_method_boundp(VALUE klass, ID id, int ex)
 {
-    rb_method_entry_t *me = rb_method_entry(klass, id);
+    rb_method_entry_t *me = rb_method_entry(klass, id, 0);
 
     if (me != 0) {
 	if ((ex & ~NOEX_RESPONDS) && (me->flag & NOEX_PRIVATE)) {
@@ -627,6 +658,8 @@ void
 rb_undef(VALUE klass, ID id)
 {
     rb_method_entry_t *me;
+    NODE *cref = rb_vm_cref();
+    VALUE omod = Qnil;
 
     if (NIL_P(klass)) {
 	rb_raise(rb_eTypeError, "no class to undef method");
@@ -642,7 +675,10 @@ rb_undef(VALUE klass, ID id)
 	rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
     }
 
-    me = search_method(klass, id);
+    if (cref && !NIL_P(cref->nd_omod)) {
+	omod = cref->nd_omod;
+    }
+    me = search_method(klass, id, omod, 0);
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	const char *s0 = " class";
@@ -665,6 +701,16 @@ rb_undef(VALUE klass, ID id)
 		      rb_id2name(id), s0, rb_class2name(c));
     }
 
+    if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
+	if (FL_TEST(me->klass, RMODULE_HAS_NESTED_METHODS)) {
+	    klass = me->klass;
+	}
+	else {
+	    VALUE mod = rb_module_new();
+	    rb_overlay_module(cref, klass, mod);
+	    klass = mod;
+	}
+    }
     rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
 
     CALL_METHOD_HOOK(klass, undefined, id);
@@ -765,7 +811,7 @@ static VALUE
 check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
 {
     const rb_method_entry_t *me;
-    me = rb_method_entry(mod, mid);
+    me = rb_method_entry(mod, mid, 0);
     if (me) {
 	if (VISI_CHECK(me->flag, noex))
 	    return Qtrue;
@@ -926,11 +972,12 @@ rb_alias(VALUE klass, ID name, ID def)
     }
 
   again:
-    orig_me = search_method(klass, def);
+    orig_me = search_method(klass, def, Qnil, 0);
 
     if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
 	if ((TYPE(klass) != T_MODULE) ||
-	    (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) {
+	    (orig_me = search_method(rb_cObject, def, Qnil, 0),
+				     UNDEFINED_METHOD_ENTRY_P(orig_me))) {
 	    rb_print_undef(klass, def, 0);
 	}
     }
@@ -1191,9 +1238,9 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
 
 	id = rb_to_id(argv[i]);
 	for (;;) {
-	    me = search_method(m, id);
+	    me = search_method(m, id, Qnil, 0);
 	    if (me == 0) {
-		me = search_method(rb_cObject, id);
+		me = search_method(rb_cObject, id, Qnil, 0);
 	    }
 	    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 		rb_print_undef(module, id, 0);
@@ -1213,7 +1260,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);
+    const rb_method_entry_t *me = rb_method_entry(klass, id, 0);
     if (me && (me->flag & NOEX_BASIC))
 	return 1;
     return 0;
