[#33000] [Ruby 1.9-Bug#4014][Open] Case-Sensitivity of Property Names Depends on Regexp Encoding — Run Paint Run Run <redmine@...>

Bug #4014: Case-Sensitivity of Property Names Depends on Regexp Encoding

11 messages 2010/11/01

[#33021] Re: [Ruby 1.9-Feature#4015][Open] File::DIRECT Constant for O_DIRECT — Yukihiro Matsumoto <matz@...>

Hi,

15 messages 2010/11/02

[#33139] [Ruby 1.9-Bug#4044][Open] Regex matching errors when using \W character class and /i option — Ben Hoskings <redmine@...>

Bug #4044: Regex matching errors when using \W character class and /i option

8 messages 2010/11/11

[#33162] Windows Unicode (chcp 65001) Generates incorrect output — Luis Lavena <luislavena@...>

Hello,

10 messages 2010/11/14

[#33246] [Ruby 1.9-Feature#4068][Open] Replace current standard Date/DateTime library with home_run — Jeremy Evans <redmine@...>

Feature #4068: Replace current standard Date/DateTime library with home_run

40 messages 2010/11/17

[#33255] [Ruby 1.9-Feature#4071][Open] support basic auth for Net::HTTP.get requests — "coderrr ." <redmine@...>

Feature #4071: support basic auth for Net::HTTP.get requests

23 messages 2010/11/19

[#33322] [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <redmine@...>

Feature #4085: Refinements and nested methods

94 messages 2010/11/24
[#33345] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Yusuke ENDOH <mame@...> 2010/11/25

Hi,

[#33356] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <shugo@...> 2010/11/25

Hi,

[#33375] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Yusuke ENDOH <mame@...> 2010/11/25

Hi,

[#33381] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <shugo@...> 2010/11/25

Hi,

[#33387] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Magnus Holm <judofyr@...> 2010/11/25

Woah, this is very nice stuff! Some comments/questions:

[#33487] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Charles Oliver Nutter <headius@...> 2010/11/30

This is a long response, and for that I apologize. I want to make sure

[#33535] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Yusuke ENDOH <mame@...> 2010/12/03

Hi,

[#33519] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <shugo@...> 2010/12/02

Hi,

[#33523] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Yusuke ENDOH <mame@...> 2010/12/02

Hi,

[#33539] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <shugo@...> 2010/12/03

Hi,

[#33543] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Yusuke ENDOH <mame@...> 2010/12/03

Hi,

[#33546] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <shugo@...> 2010/12/03

Hi,

[#33548] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Yusuke ENDOH <mame@...> 2010/12/03

Hi,

[#33567] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Shugo Maeda <shugo@...> 2010/12/04

Hi,

[#33595] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods — Charles Oliver Nutter <headius@...> 2010/12/06

On Sat, Dec 4, 2010 at 6:32 AM, Shugo Maeda <shugo@ruby-lang.org> wrote:

[#33367] Planning to release 1.8.7 fixes on 12/25 (Japanese timezone) — Urabe Shyouhei <shyouhei@...>

Hello,

20 messages 2010/11/25
[#33439] Re: Planning to release 1.8.7 fixes on 12/25 (Japanese timezone) — Luis Lavena <luislavena@...> 2010/11/27

2010/11/25 Urabe Shyouhei <shyouhei@ruby-lang.org>:

[#33456] [Request for Comment] avoid timer thread — SASADA Koichi <ko1@...>

Hi,

25 messages 2010/11/29
[#35152] Re: [Request for Comment] avoid timer thread — Mark Somerville <mark@...> 2011/02/08

On Mon, Nov 29, 2010 at 11:53:03AM +0900, SASADA Koichi wrote:

[#36077] Re: [Request for Comment] avoid timer thread — Mark Somerville <mark@...> 2011/05/09

On Tue, Feb 08, 2011 at 09:24:13PM +0900, Mark Somerville wrote:

[#36952] Re: [Request for Comment] avoid timer thread — Eric Wong <normalperson@...> 2011/06/10

Mark Somerville <mark@scottishclimbs.com> wrote:

[#37080] Re: [Request for Comment] avoid timer thread — Mark Somerville <mark@...> 2011/06/13

On Sat, Jun 11, 2011 at 05:57:11AM +0900, Eric Wong wrote:

[#37103] Re: [Request for Comment] avoid timer thread — Eric Wong <normalperson@...> 2011/06/13

Mark Somerville <mark@scottishclimbs.com> wrote:

[#37187] Re: [Request for Comment] avoid timer thread — SASADA Koichi <ko1@...> 2011/06/16

(2011/06/14 3:37), Eric Wong wrote:

[#37195] Re: [Request for Comment] avoid timer thread — Eric Wong <normalperson@...> 2011/06/17

SASADA Koichi <ko1@atdot.net> wrote:

[#37205] Re: [Request for Comment] avoid timer thread — Eric Wong <normalperson@...> 2011/06/17

Eric Wong <normalperson@yhbt.net> wrote:

[#33469] [Ruby 1.9-Feature#4100][Open] Improve Net::HTTP documentation — Eric Hodel <redmine@...>

Feature #4100: Improve Net::HTTP documentation

12 messages 2010/11/29

[ruby-core:33322] [Ruby 1.9-Feature#4085][Open] Refinements and nested methods

From: Shugo Maeda <redmine@...>
Date: 2010-11-24 13:12:24 UTC
List: ruby-core #33322
Feature #4085: Refinements and nested methods
http://redmine.ruby-lang.org/issues/show/4085

Author: Shugo Maeda
Status: Open, Priority: Normal
Category: core, Target version: 1.9.3

As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."

Refinements are similar to Classboxes.  However, Refinements doesn't
support local rebinding as mentioned later.  In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.

In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions.  Such class extensions are called refinements.  For
example, the following module refines Fixnum.

  module MathN
    refine Fixnum do
      def /(other) quo(other) end
    end
  end

Module#refine(klass) takes one argument, which is a class to be
extended.  Module#refine also takes a block, where additional or
overriding methods of klass can be defined.  In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.

This refinement can be enabled by the method using.

  class Foo
    using MathN

    def foo
      p 1 / 2
    end
  end

  f =3D Foo.new
  f.foo #=3D> (1/2)
  p 1 / 2

In this example, the refinement in MathN is enabled in the definition
of Foo.  The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using.  If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped.  For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:

  class Foo
    def bar
      puts "Foo#bar"
    end

    def baz
      bar
    end
  end

  module FooExt
    refine Foo do
      def bar
        puts "FooExt#bar"
      end
    end
  end

  module Quux
    using FooExt

    foo =3D Foo.new
    foo.bar  # =3D> FooExt#bar
    foo.baz  # =3D> Foo#bar
  end

Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.

  class Foo
    using MathN
  end

  class Foo
    # MathN is enabled in a reopened definition.
    p 1 / 2  #=3D> (1/2)
  end

  class Bar < Foo
    # MathN is enabled in a subclass definition.
    p 1 / 2  #=3D> (1/2)
  end

If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.

  module A
    using MathN
  end
  class B
    using MathN
  end
  MathN.module_eval do
    p 1 / 2  #=3D> (1/2)
  end
  A.module_eval do
    p 1 / 2  #=3D> (1/2)
  end
  B.class_eval do
    p 1 / 2  #=3D> (1/2)
  end
  B.new.instance_eval do
    p 1 / 2  #=3D> (1/2)
  end

Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method=
.

  def foo
    def bar
      puts "bar"
    end
    bar
  end
  foo  #=3D> bar
  bar  #=3D> bar

In Ruby, there are no functions, but only methods.  So there are no
right places where nested methods are defined.  However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place.  For example, the above code is
almost equivalent to the following code:

  def foo
    klass =3D self.class
    m =3D Module.new {
      refine klass do
        def bar
          puts "bar"
        end
      end
    }
    using m
    bar
  end
  foo  #=3D> bar
  bar  #=3D> NoMethodError

The attached patch is based on SVN trunk r29837.


----------------------------------------
http://redmine.ruby-lang.org

Attachments (1)

refinement-r29837-20101124.diff (70.3 KB, text/x-diff)
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index 8d0db6e..c6c3b09 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 2241792..5c7835b 100644
--- a/class.c
+++ b/class.c
@@ -617,8 +617,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);
 
@@ -685,7 +685,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:
@@ -1387,7 +1387,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 b9749f4..8875e57 100644
--- a/compile.c
+++ b/compile.c
@@ -4575,7 +4575,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 bbf66b3..060e6f8 100644
--- a/eval.c
+++ b/eval.c
@@ -23,6 +23,8 @@ VALUE proc_invoke(VALUE, VALUE, VALUE, VALUE);
 VALUE rb_binding_new(void);
 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;
@@ -858,6 +860,146 @@ rb_mod_include(int argc, VALUE *argv, VALUE module)
 }
 
 void
+rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
+{
+    VALUE iclass, c, superclass = klass;
+
+    Check_Type(klass, T_CLASS);
+    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;
+	    while (c && TYPE(c) == T_ICLASS) {
+		if (RBASIC(c)->klass == module) {
+		    /* already overlayed module */
+		    return;
+		}
+		c = RCLASS_SUPER(c);
+	    }
+	}
+    }
+    FL_SET(module, RMODULE_IS_OVERLAYED);
+    c = iclass = rb_include_class_new(module, superclass);
+    module = RCLASS_SUPER(module);
+    while (module) {
+	FL_SET(module, RMODULE_IS_OVERLAYED);
+	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);
+}
+
+static int
+using_module_i(VALUE klass, VALUE module, VALUE arg)
+{
+    NODE *cref = (NODE *) arg;
+    int i;
+
+    rb_overlay_module(cref, klass, module);
+    return ST_CONTINUE;
+}
+
+void
+rb_using_module(NODE *cref, VALUE module)
+{
+    ID id_overlayed_modules;
+    VALUE overlayed_modules;
+
+    Check_Type(module, T_MODULE);
+    CONST_ID(id_overlayed_modules, "__overlayed_modules__");
+    overlayed_modules = rb_attr_get(module, id_overlayed_modules);
+    if (NIL_P(overlayed_modules)) return;
+    rb_hash_foreach(overlayed_modules, using_module_i, (VALUE) cref);
+}
+
+/*
+ *  call-seq:
+ *     using(module)    -> self
+ *
+ *  Import class refinements from <i>module</i> into the receiver.
+ */
+
+static VALUE
+rb_mod_using(VALUE self, VALUE module)
+{
+    NODE *cref = rb_vm_cref();
+    ID id_using_modules;
+    VALUE using_modules;
+
+    CONST_ID(id_using_modules, "__using_modules__");
+    using_modules = rb_attr_get(self, id_using_modules);
+    if (NIL_P(using_modules)) {
+	using_modules = rb_hash_new();
+	rb_funcall(using_modules, rb_intern("compare_by_identity"), 0);
+	rb_ivar_set(self, id_using_modules, using_modules);
+    }
+    rb_hash_aset(using_modules, module, Qtrue);
+    rb_using_module(cref, module);
+    rb_funcall(module, rb_intern("used"), 1, self);
+    return self;
+}
+
+void rb_redefine_opt_method(VALUE, ID);
+
+static VALUE
+refinement_module_method_added(VALUE mod, VALUE mid)
+{
+    ID id = SYM2ID(mid);
+    ID id_refined_class;
+    VALUE klass;
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    klass = rb_ivar_get(mod, id_refined_class);
+    rb_redefine_opt_method(klass, id);
+}
+
+/*
+ *  call-seq:
+ *     refine(klass) { block }   -> self
+ *
+ *  Refine <i>klass</i> in the receiver.
+ */
+
+static VALUE
+rb_mod_refine(VALUE module, VALUE klass)
+{
+    NODE *cref = rb_vm_cref();
+    VALUE mod;
+    ID id_overlayed_modules, id_refined_class;
+    VALUE overlayed_modules, modules;
+
+    Check_Type(klass, T_CLASS);
+    CONST_ID(id_overlayed_modules, "__overlayed_modules__");
+    overlayed_modules = rb_attr_get(module, id_overlayed_modules);
+    if (NIL_P(overlayed_modules)) {
+	overlayed_modules = rb_hash_new();
+	rb_funcall(overlayed_modules, rb_intern("compare_by_identity"), 0);
+	rb_ivar_set(module, id_overlayed_modules, overlayed_modules);
+    }
+    mod = rb_hash_aref(overlayed_modules, klass);
+    if (NIL_P(mod)) {
+	mod = rb_module_new();
+	CONST_ID(id_refined_class, "__refined_class__");
+	rb_ivar_set(mod, id_refined_class, klass);
+	rb_define_singleton_method(mod, "method_added",
+				   refinement_module_method_added, 1);
+	rb_overlay_module(cref, klass, mod);
+	rb_hash_aset(overlayed_modules, klass, mod);
+    }
+    rb_mod_module_eval(0, NULL, mod);
+    return mod;
+}
+
+void
 rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
 {
     PASS_PASSED_BLOCK();
@@ -969,6 +1111,22 @@ top_include(int argc, VALUE *argv, VALUE self)
     return rb_mod_include(argc, argv, rb_cObject);
 }
 
+/*
+ *  call-seq:
+ *     using(module)    -> self
+ *
+ *  Import class refinements from <i>module</i> into the scope where <code>use</code> is called.
+ */
+
+static VALUE
+f_using(VALUE self, VALUE module)
+{
+    NODE *cref = rb_vm_cref();
+
+    rb_using_module(cref, module);
+    return self;
+}
+
 VALUE rb_f_trace_var();
 VALUE rb_f_untrace_var();
 
@@ -1121,6 +1279,8 @@ Init_eval(void)
     rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
     rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
     rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
+    rb_define_private_method(rb_cModule, "using", rb_mod_using, 1);
+    rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
 
     rb_undef_method(rb_cClass, "module_function");
 
@@ -1136,6 +1296,8 @@ Init_eval(void)
 
     rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1);
 
+    rb_define_global_function("using", f_using, 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 cf9107a..c3309ee 100644
--- a/gc.c
+++ b/gc.c
@@ -1684,6 +1684,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 b18a1f5..e8f3543 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -164,11 +164,13 @@ void rb_singleton_class_attached(VALUE,VALUE);
 VALUE rb_make_metaclass(VALUE, VALUE);
 void rb_check_inheritable(VALUE);
 VALUE rb_class_inherited(VALUE, VALUE);
+VALUE rb_mod_opened(VALUE);
 VALUE rb_define_class_id(ID, VALUE);
 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);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 4e15517..3e1d08f 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -629,6 +629,8 @@ struct RClass {
 #define RMODULE_CONST_TBL(m) RCLASS_CONST_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
+#define RMODULE_IS_OVERLAYED FL_USER3
 
 struct RFloat {
     struct RBasic basic;
diff --git a/insns.def b/insns.def
index e45609b..6e71f6c 100644
--- a/insns.def
+++ b/insns.def
@@ -183,8 +183,8 @@ getclassvariable
 ()
 (VALUE val)
 {
-    NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
-    val = rb_cvar_get(vm_get_cvar_base(cref), id);
+    NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
+    val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id);
 }
 
 /**
@@ -198,8 +198,8 @@ setclassvariable
 (VALUE val)
 ()
 {
-    NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
-    rb_cvar_set(vm_get_cvar_base(cref), id, val);
+    NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
+    rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val);
 }
 
 /**
@@ -792,7 +792,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)) {
@@ -964,9 +964,10 @@ 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);
+    rb_vm_using_modules(class_iseq->cref_stack, klass);
     RESTORE_REGS();
 
     INC_VM_STATE_VERSION();
@@ -996,7 +997,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;
     VALUE flag = op_flag;
     int num = caller_setup_args(th, GET_CFP(), flag, (int)op_argc,
@@ -1006,8 +1007,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);
 }
 
 /**
@@ -1030,20 +1031,25 @@ invokesuper
     VALUE recv, klass;
     ID id;
     const rb_method_entry_t *me;
+    rb_iseq_t *ip;
 
     flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
 
     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;
+    }
+    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);
+	me = rb_method_entry_get_with_omod(Qnil, klass, id, &klass);
     }
 
-    me = rb_method_entry(klass, id);
-
-    CALL_METHOD(num, blockptr, flag, id, me, recv);
+    CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
 }
 
 /**
@@ -1668,7 +1674,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)) {
@@ -2069,7 +2075,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 2b82aa8..7542969 100644
--- a/iseq.c
+++ b/iseq.c
@@ -182,20 +182,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;
@@ -1368,7 +1368,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/lex.c.blt b/lex.c.blt
index 1ae8099..a7de0fb 100644
--- a/lex.c.blt
+++ b/lex.c.blt
@@ -1,5 +1,5 @@
-/* C code produced by gperf version 3.0.4 */
-/* Command-line: gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' defs/keywords  */
+/* C code produced by gperf version 3.0.3 */
+/* Command-line: gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' ../defs/keywords  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -28,14 +28,14 @@
 error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
 #endif
 
-#line 1 "defs/keywords"
+#line 1 "../defs/keywords"
 
 struct kwtable {const char *name; int id[2]; enum lex_state_e state;};
 const struct kwtable *rb_reserved_word(const char *, unsigned int);
 #ifndef RIPPER
 static const struct kwtable *reserved_word(const char *, unsigned int);
 #define rb_reserved_word(str, len) reserved_word(str, len)
-#line 9 "defs/keywords"
+#line 9 "../defs/keywords"
 struct kwtable;
 
 #define TOTAL_KEYWORDS 41
@@ -103,7 +103,7 @@ hash (str, len)
 
 #ifdef __GNUC__
 __inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+#ifdef __GNUC_STDC_INLINE__
 __attribute__ ((__gnu_inline__))
 #endif
 #endif
@@ -115,88 +115,88 @@ rb_reserved_word (str, len)
   static const struct kwtable wordlist[] =
     {
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 19 "defs/keywords"
+#line 19 "../defs/keywords"
       {"break", {keyword_break, keyword_break}, EXPR_MID},
-#line 25 "defs/keywords"
+#line 25 "../defs/keywords"
       {"else", {keyword_else, keyword_else}, EXPR_BEG},
-#line 35 "defs/keywords"
+#line 35 "../defs/keywords"
       {"nil", {keyword_nil, keyword_nil}, EXPR_END},
-#line 28 "defs/keywords"
+#line 28 "../defs/keywords"
       {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG},
-#line 27 "defs/keywords"
+#line 27 "../defs/keywords"
       {"end", {keyword_end, keyword_end}, EXPR_END},
-#line 44 "defs/keywords"
+#line 44 "../defs/keywords"
       {"then", {keyword_then, keyword_then}, EXPR_BEG},
-#line 36 "defs/keywords"
+#line 36 "../defs/keywords"
       {"not", {keyword_not, keyword_not}, EXPR_ARG},
-#line 29 "defs/keywords"
+#line 29 "../defs/keywords"
       {"false", {keyword_false, keyword_false}, EXPR_END},
-#line 42 "defs/keywords"
+#line 42 "../defs/keywords"
       {"self", {keyword_self, keyword_self}, EXPR_END},
-#line 26 "defs/keywords"
+#line 26 "../defs/keywords"
       {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE},
-#line 39 "defs/keywords"
+#line 39 "../defs/keywords"
       {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID},
-#line 45 "defs/keywords"
+#line 45 "../defs/keywords"
       {"true", {keyword_true, keyword_true}, EXPR_END},
-#line 48 "defs/keywords"
+#line 48 "../defs/keywords"
       {"until", {keyword_until, modifier_until}, EXPR_VALUE},
-#line 47 "defs/keywords"
+#line 47 "../defs/keywords"
       {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE},
-#line 41 "defs/keywords"
+#line 41 "../defs/keywords"
       {"return", {keyword_return, keyword_return}, EXPR_MID},
-#line 22 "defs/keywords"
+#line 22 "../defs/keywords"
       {"def", {keyword_def, keyword_def}, EXPR_FNAME},
-#line 17 "defs/keywords"
+#line 17 "../defs/keywords"
       {"and", {keyword_and, keyword_and}, EXPR_VALUE},
-#line 24 "defs/keywords"
+#line 24 "../defs/keywords"
       {"do", {keyword_do, keyword_do}, EXPR_BEG},
-#line 51 "defs/keywords"
+#line 51 "../defs/keywords"
       {"yield", {keyword_yield, keyword_yield}, EXPR_ARG},
-#line 30 "defs/keywords"
+#line 30 "../defs/keywords"
       {"for", {keyword_for, keyword_for}, EXPR_VALUE},
-#line 46 "defs/keywords"
+#line 46 "../defs/keywords"
       {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME},
-#line 37 "defs/keywords"
+#line 37 "../defs/keywords"
       {"or", {keyword_or, keyword_or}, EXPR_VALUE},
-#line 32 "defs/keywords"
+#line 32 "../defs/keywords"
       {"in", {keyword_in, keyword_in}, EXPR_VALUE},
-#line 49 "defs/keywords"
+#line 49 "../defs/keywords"
       {"when", {keyword_when, keyword_when}, EXPR_VALUE},
-#line 40 "defs/keywords"
+#line 40 "../defs/keywords"
       {"retry", {keyword_retry, keyword_retry}, EXPR_END},
-#line 31 "defs/keywords"
+#line 31 "../defs/keywords"
       {"if", {keyword_if, modifier_if}, EXPR_VALUE},
-#line 20 "defs/keywords"
+#line 20 "../defs/keywords"
       {"case", {keyword_case, keyword_case}, EXPR_VALUE},
-#line 38 "defs/keywords"
+#line 38 "../defs/keywords"
       {"redo", {keyword_redo, keyword_redo}, EXPR_END},
-#line 34 "defs/keywords"
+#line 34 "../defs/keywords"
       {"next", {keyword_next, keyword_next}, EXPR_MID},
-#line 43 "defs/keywords"
+#line 43 "../defs/keywords"
       {"super", {keyword_super, keyword_super}, EXPR_ARG},
-#line 33 "defs/keywords"
+#line 33 "../defs/keywords"
       {"module", {keyword_module, keyword_module}, EXPR_VALUE},
-#line 18 "defs/keywords"
+#line 18 "../defs/keywords"
       {"begin", {keyword_begin, keyword_begin}, EXPR_BEG},
-#line 12 "defs/keywords"
+#line 12 "../defs/keywords"
       {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END},
-#line 13 "defs/keywords"
+#line 13 "../defs/keywords"
       {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END},
-#line 11 "defs/keywords"
+#line 11 "../defs/keywords"
       {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
-#line 15 "defs/keywords"
+#line 15 "../defs/keywords"
       {"END", {keyword_END, keyword_END}, EXPR_END},
-#line 16 "defs/keywords"
+#line 16 "../defs/keywords"
       {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME},
-#line 14 "defs/keywords"
+#line 14 "../defs/keywords"
       {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END},
-#line 23 "defs/keywords"
+#line 23 "../defs/keywords"
       {"defined?", {keyword_defined, keyword_defined}, EXPR_ARG},
-#line 21 "defs/keywords"
+#line 21 "../defs/keywords"
       {"class", {keyword_class, keyword_class}, EXPR_CLASS},
       {""}, {""},
-#line 50 "defs/keywords"
+#line 50 "../defs/keywords"
       {"while", {keyword_while, modifier_while}, EXPR_VALUE}
     };
 
@@ -214,6 +214,6 @@ rb_reserved_word (str, len)
     }
   return 0;
 }
-#line 52 "defs/keywords"
+#line 52 "../defs/keywords"
 
 #endif
diff --git a/method.h b/method.h
index 3cfe438..4750b45 100644
--- a/method.h
+++ b/method.h
@@ -89,9 +89,10 @@ 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_with_omod(VALUE omod, VALUE klass, ID id, VALUE *define_class_ptr);
+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/object.c b/object.c
index 75192c1..480266a 100644
--- a/object.c
+++ b/object.c
@@ -2531,6 +2531,7 @@ Init_Object(void)
     rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1);
+    rb_define_private_method(rb_cModule, "used", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1);
diff --git a/parse.y b/parse.y
index 13e18f2..67ca1f1 100644
--- a/parse.y
+++ b/parse.y
@@ -2967,6 +2967,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..87cf3c1 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;
 };
@@ -861,6 +862,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 +905,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 +913,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 +955,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 +976,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 +1088,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 +1425,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 +1652,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);
 }
 
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/test/ruby/test_nested_method.rb b/test/ruby/test_nested_method.rb
new file mode 100644
index 0000000..2b22fd4
--- /dev/null
+++ b/test/ruby/test_nested_method.rb
@@ -0,0 +1,29 @@
+require 'test/unit'
+
+class TestNestedMethod < Test::Unit::TestCase
+  def call_nested_method
+    def foo
+      return "foo"
+    end
+
+    return foo
+  end
+
+  def test_nested_method
+    assert_equal("foo", call_nested_method)
+    assert_raise(NoMethodError) { foo() }
+  end
+
+  def test_doubly_nested_method
+    def call_doubly_nested_method
+      def foo
+        return "foo"
+      end
+
+      return foo
+    end
+
+    assert_equal("foo", call_doubly_nested_method)
+    assert_raise(NoMethodError) { foo() }
+  end
+end
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
new file mode 100644
index 0000000..c880643
--- /dev/null
+++ b/test/ruby/test_refinement.rb
@@ -0,0 +1,210 @@
+require 'test/unit'
+
+class TestRefinement < Test::Unit::TestCase
+  class Foo
+    def x
+      return "Foo#x"
+    end
+
+    def y
+      return "Foo#y"
+    end
+
+    def call_x
+      return x
+    end
+  end
+
+  module FooExt
+    refine Foo do
+      def x
+        return "FooExt#x"
+      end
+
+      def y
+        return "FooExt#y " + super
+      end
+
+      def z
+        return "FooExt#z"
+      end
+    end
+  end
+
+  module FooExt2
+    refine Foo do
+      def x
+        return "FooExt2#x"
+      end
+
+      def y
+        return "FooExt2#y " + super
+      end
+
+      def z
+        return "FooExt2#z"
+      end
+    end
+  end
+
+  class FooSub < Foo
+    def x
+      return "FooSub#x"
+    end
+
+    def y
+      return "FooSub#y " + super
+    end
+  end
+
+  class FooExtClient
+    using FooExt
+
+    def self.invoke_x_on(foo)
+      return foo.x
+    end
+
+    def self.invoke_y_on(foo)
+      return foo.y
+    end
+
+    def self.invoke_z_on(foo)
+      return foo.z
+    end
+
+    def self.invoke_call_x_on(foo)
+      return foo.call_x
+    end
+  end
+
+  class FooExtClient2
+    using FooExt
+    using FooExt2
+
+    def self.invoke_y_on(foo)
+      return foo.y
+    end
+  end
+
+  def test_override
+    foo = Foo.new
+    assert_equal("Foo#x", foo.x)
+    assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo))
+    assert_equal("Foo#x", foo.x)
+  end
+
+  def test_super
+    foo = Foo.new
+    assert_equal("Foo#y", foo.y)
+    assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo))
+    assert_equal("Foo#y", foo.y)
+  end
+
+  def test_super_chain
+    foo = Foo.new
+    assert_equal("Foo#y", foo.y)
+    assert_equal("FooExt2#y FooExt#y Foo#y", FooExtClient2.invoke_y_on(foo))
+    assert_equal("Foo#y", foo.y)
+  end
+
+  def test_new_method
+    foo = Foo.new
+    assert_raise(NoMethodError) { foo.z }
+    assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo))
+    assert_raise(NoMethodError) { foo.z }
+  end
+
+  def test_no_local_rebinding
+    foo = Foo.new
+    assert_equal("Foo#x", foo.call_x)
+    assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo))
+    assert_equal("Foo#x", foo.call_x)
+  end
+
+  def test_subclass_is_prior
+    sub = FooSub.new
+    assert_equal("FooSub#x", sub.x)
+    assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
+    assert_equal("FooSub#x", sub.x)
+  end
+
+  def test_subclass_is_prior
+    sub = FooSub.new
+    assert_equal("FooSub#x", sub.x)
+    assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
+    assert_equal("FooSub#x", sub.x)
+  end
+
+  def test_super_in_subclass
+    sub = FooSub.new
+    assert_equal("FooSub#y Foo#y", sub.y)
+    # not "FooSub#y FooExt#y Foo#y"
+    assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub))
+    assert_equal("FooSub#y Foo#y", sub.y)
+  end
+
+  def test_new_method_on_subclass
+    sub = FooSub.new
+    assert_raise(NoMethodError) { sub.z }
+    assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub))
+    assert_raise(NoMethodError) { sub.z }
+  end
+
+  def test_module_eval
+    foo = Foo.new
+    assert_equal("Foo#x", foo.x)
+    assert_equal("FooExt#x", FooExt.module_eval { foo.x })
+    assert_equal("Foo#x", foo.x)
+  end
+
+  def test_instance_eval
+    foo = Foo.new
+    ext_client = FooExtClient.new
+    assert_equal("Foo#x", foo.x)
+    assert_equal("FooExt#x", ext_client.instance_eval { foo.x })
+    assert_equal("Foo#x", foo.x)
+  end
+
+  def test_override_builtin_method
+    m = Module.new {
+      refine Fixnum do
+        def /(other) quo(other) end
+      end
+    }
+    assert_equal(0, 1 / 2)
+    assert_equal(Rational(1, 2), m.module_eval { 1 / 2 })
+    assert_equal(0, 1 / 2)
+  end
+
+  def test_return_value_of_refine
+    mod = nil
+    result = nil
+    m = Module.new {
+      result = refine(Object) {
+        mod = self
+      }
+    }
+    assert_equal mod, result
+  end
+
+  def test_refine_same_class_twice
+    result1 = nil
+    result2 = nil
+    result3 = nil
+    m = Module.new {
+      result1 = refine(Fixnum) {
+        def foo; return "foo" end
+      }
+      result2 = refine(Fixnum) {
+        def bar; return "bar" end
+      }
+      result3 = refine(String) {
+        def baz; return "baz" end
+      }
+    }
+    assert_equal("foo", m.module_eval { 1.foo })
+    assert_equal("bar", m.module_eval { 1.bar })
+    assert_equal(result1, result2)
+    assert_not_equal(result1, result3)
+  end
+end
diff --git a/vm.c b/vm.c
index 980e7ea..ae9af7e 100644
--- a/vm.c
+++ b/vm.c
@@ -70,7 +70,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;
@@ -90,7 +90,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);
@@ -105,7 +105,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);
 
@@ -490,6 +490,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;
@@ -539,9 +540,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;
 	th->passed_block = blockptr;
@@ -816,7 +819,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
@@ -1317,7 +1321,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;
@@ -1455,7 +1460,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);
 
@@ -1667,6 +1672,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);
 
@@ -1778,7 +1784,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;
@@ -1815,14 +1821,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);
 
@@ -1847,12 +1876,43 @@ 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) {
+	VALUE c;
+       	if (TYPE(klass) == T_MODULE) {
+	    c = rb_obj_class(th->cfp->self);
+	}
+	else {
+	    c = klass;
+	}
+	if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
+	    target = Qnil;
+	}
+	else {
+	    target = find_module_for_nested_methods(cref, c);
+	}
+	if (NIL_P(target)) {
+	    target = rb_module_new();
+	    FL_SET(target, RMODULE_HAS_NESTED_METHODS);
+	    rb_overlay_module(cref, c, 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->cref_stack->nd_visi = NOEX_PUBLIC;
-    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);
@@ -1866,10 +1926,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;
 }
@@ -1878,7 +1938,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;
 }
@@ -1994,7 +2054,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);
diff --git a/vm_core.h b/vm_core.h
index 1ea9413..5a5d08e 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -132,6 +132,9 @@ struct iseq_inline_cache_entry {
 	rb_method_entry_t *method;
 	long index;
     } ic_value;
+    union {
+	VALUE defined_class;
+    } ic_value2;
 };
 
 #if 1
@@ -325,16 +328,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;
@@ -392,6 +397,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;
@@ -711,6 +717,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 c67e54c..73dbd48 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
@@ -1212,6 +1213,7 @@ yield_under(VALUE under, VALUE self, VALUE values)
     }
     cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
     cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL;
+    rb_vm_using_modules(cref, under);
 
     if (values == Qundef) {
 	return vm_yield_with_cref(th, 1, &self, cref);
@@ -1233,6 +1235,7 @@ eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line)
     else {
 	SafeStringValue(src);
     }
+    rb_vm_using_modules(cref, under);
 
     return eval_string_with_cref(self, src, Qnil, cref, file, line);
 }
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 18c22cb..6bb6f5b 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -23,7 +23,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)
 {
@@ -62,6 +62,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
@@ -387,7 +399,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;
@@ -396,7 +408,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;
 
@@ -415,13 +428,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);
@@ -452,7 +467,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;
@@ -475,7 +490,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 */;
@@ -498,7 +514,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);
     }
 }
@@ -506,7 +523,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;
 
@@ -517,12 +535,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:{
@@ -553,12 +573,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;
@@ -584,7 +605,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;
@@ -627,8 +648,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;
 		}
@@ -720,7 +739,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);
 
     if (blockargptr) {
@@ -938,7 +957,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);
 
@@ -1071,13 +1091,13 @@ vm_get_cref0(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
     }
 }
 
-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 = vm_get_cref0(iseq, lfp, dfp);
 
     if (cref == 0) {
-	rb_bug("vm_get_cref: unreachable");
+	rb_bug("rb_vm_get_cref: unreachable");
     }
     return cref;
 }
@@ -1086,8 +1106,8 @@ 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) {
@@ -1096,6 +1116,11 @@ vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
     else if (cfp) {
 	cref->nd_next = vm_get_cref0(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;
 }
@@ -1103,7 +1128,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) {
@@ -1119,7 +1144,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,6 +1172,20 @@ vm_check_if_namespace(VALUE klass)
 }
 
 static inline VALUE
+vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
+{
+    if (TYPE(klass) == T_MODULE &&
+	FL_TEST(klass, RMODULE_IS_OVERLAYED) &&
+	TYPE(cfp->klass) == T_ICLASS &&
+	RBASIC(cfp->klass)->klass == klass) {
+	return cfp->klass;
+    }
+    else {
+	return klass;
+    }
+}
+
+static inline VALUE
 vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
 		VALUE orig_klass, ID id, int is_defined)
 {
@@ -1154,7 +1193,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;
 
@@ -1193,7 +1232,7 @@ vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
 
 	/* search self */
 	if (root_cref && !NIL_P(root_cref->nd_clss)) {
-	    klass = root_cref->nd_clss;
+	    klass = vm_get_iclass(th->cfp, root_cref->nd_clss);
 	}
 	else {
 	    klass = CLASS_OF(th->cfp->self);
@@ -1218,7 +1257,7 @@ vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
 }
 
 static inline VALUE
-vm_get_cvar_base(NODE *cref)
+vm_get_cvar_base(NODE *cref, rb_control_frame_t *cfp)
 {
     VALUE klass;
 
@@ -1232,7 +1271,7 @@ vm_get_cvar_base(NODE *cref)
 	}
     }
 
-    klass = cref->nd_clss;
+    klass = vm_get_iclass(cfp, cref->nd_clss);
 
     if (NIL_P(klass)) {
 	rb_raise(rb_eTypeError, "no class variables available");
@@ -1333,22 +1372,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;
 }
@@ -1356,7 +1401,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) {
@@ -1417,10 +1462,10 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq,
 	}
 
 	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(iseq->klass, recv);
+	klass = vm_search_normal_superclass(reg_cfp->klass, recv);
     }
 
     *idp = id;
@@ -1690,7 +1735,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)) {
@@ -1701,3 +1746,43 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic)
     return Qundef;
 }
 
+void rb_using_module(NODE *cref, VALUE module);
+
+static int
+vm_using_module_i(VALUE module, VALUE value, VALUE arg)
+{
+    NODE *cref = (NODE *) arg;
+
+    rb_using_module(cref, module);
+    return ST_CONTINUE;
+}
+
+static void
+rb_vm_using_modules(NODE *cref, VALUE klass)
+{
+    ID id_using_modules;
+    VALUE using_modules;
+
+    CONST_ID(id_using_modules, "__using_modules__");
+    using_modules = rb_attr_get(klass, id_using_modules);
+    switch (TYPE(klass)) {
+    case T_CLASS:
+	if (NIL_P(using_modules)) {
+	    VALUE super = rb_class_real(RCLASS_SUPER(klass));
+	    using_modules = rb_attr_get(super, id_using_modules);
+	    if (!NIL_P(using_modules)) {
+		using_modules = rb_hash_dup(using_modules);
+		rb_ivar_set(klass, id_using_modules, using_modules);
+	    }
+	}
+	break;
+    case T_MODULE:
+	rb_using_module(cref, klass);
+	break;
+    }
+    if (!NIL_P(using_modules)) {
+	rb_hash_foreach(using_modules, vm_using_module_i,
+		       	(VALUE) cref);
+    }
+}
+
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 fa5738b..2d362f7 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];
@@ -381,7 +383,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;
@@ -392,20 +394,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;
 }
 
@@ -416,14 +430,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;
@@ -436,20 +455,39 @@ 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_get_with_omod(VALUE omod, VALUE klass, ID id,
+			      VALUE *defined_class_ptr)
 {
     struct cache_entry *ent;
 
-    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);
+}
+
+rb_method_entry_t *
+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;
+    }
+    return rb_method_entry_get_with_omod(omod, klass, id, defined_class_ptr);
 }
 
 static void
@@ -535,14 +573,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)) {
@@ -552,7 +591,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 {
@@ -564,7 +603,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)) {
@@ -628,6 +667,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");
@@ -643,7 +684,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";
@@ -666,6 +710,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);
@@ -766,7 +820,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;
@@ -927,11 +981,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);
 	}
     }
@@ -1192,9 +1247,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);
@@ -1214,7 +1269,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;
@@ -1300,6 +1355,20 @@ obj_respond_to_missing(VALUE obj, VALUE priv)
 }
 
 void
+rb_redefine_opt_method(VALUE klass, ID mid)
+{
+    st_data_t key, data;
+    rb_method_entry_t *me = 0;
+
+    if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
+	!(me = (rb_method_entry_t *)data) ||
+	(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
+	return;
+    }
+    rb_vm_check_redefinition_opt_method(me);
+}
+
+void
 Init_eval_method(void)
 {
 #undef rb_intern

In This Thread

Prev Next