diff --git a/class.c b/class.c
index ac39863..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:
diff --git a/eval.c b/eval.c
index bbf66b3..6d5af7b 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,180 @@ 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);
+}
+
+static VALUE
+refinement_module_include(int argc, VALUE *argv, VALUE module)
+{
+    rb_thread_t *th = GET_THREAD();
+    rb_control_frame_t *cfp = th->cfp;
+    rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
+    VALUE result = rb_mod_include(argc, argv, module);
+    NODE *cref;
+    ID id_refined_class;
+    VALUE klass, c;
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    klass = rb_attr_get(module, id_refined_class);
+    while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
+	if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) &&
+	    (cref = rb_vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp)) &&
+	    !NIL_P(cref->nd_omod) &&
+	    !NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
+	    while (argc--) {
+		VALUE mod = argv[argc];
+		if (rb_class_inherited_p(module, mod)) {
+		    RCLASS_SUPER(c) =
+			rb_include_class_new(mod, RCLASS_SUPER(c));
+		}
+	    }
+	    break;
+	}
+	cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+    }
+    return result;
+}
+
+/*
+ *  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_define_singleton_method(mod, "include",
+				   refinement_module_include, -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 +1145,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 +1313,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 +1330,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..7cc75b2 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);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 4e15517..1d2546a 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -629,6 +629,7 @@ 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_IS_OVERLAYED FL_USER2
 
 struct RFloat {
     struct RBasic basic;
diff --git a/insns.def b/insns.def
index 5974cb2..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);
 }
 
 /**
@@ -967,6 +967,7 @@ defineclass
 		  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();
@@ -1041,12 +1042,11 @@ invokesuper
     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_get_with_omod(Qnil, klass, id, &klass);
     }
 
     CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
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/method.h b/method.h
index c967a69..4750b45 100644
--- a/method.h
+++ b/method.h
@@ -91,7 +91,8 @@ void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc,
 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, VALUE *define_class_ptr);
 
-rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
+rb_method_entry_t *rb_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..b76e141 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,10 @@ 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_CREF_OMOD_SHARED, 7:NODE_FL_NEWLINE */
 #define NODE_FL_NEWLINE (((VALUE)1)<<7)
 #define NODE_FL_CREF_PUSHED_BY_EVAL NODE_FL_NEWLINE
+#define NODE_FL_CREF_OMOD_SHARED (((VALUE)1)<<6)
 
 #define NODE_TYPESHIFT 8
 #define NODE_TYPEMASK  (((VALUE)0x7f)<<NODE_TYPESHIFT)
@@ -277,6 +283,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 +442,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/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
new file mode 100644
index 0000000..05a4f33
--- /dev/null
+++ b/test/ruby/test_refinement.rb
@@ -0,0 +1,311 @@
+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
+
+  def test_respond_to?
+    m = Module.new {
+      refine Fixnum do
+        def foo; "foo"; end
+      end
+    }
+    assert_equal(false, 1.respond_to?(:foo))
+    assert_equal(true, m.module_eval { 1.respond_to?(:foo) })
+    assert_equal(false, 1.respond_to?(:foo))
+  end
+
+  def test_builtin_method_no_local_rebinding
+    m = Module.new {
+      refine String do
+        def <=>(other) return 0 end
+      end
+    }
+    assert_equal(false, m.module_eval { "1" >= "2" })
+
+    m2 = Module.new {
+      refine Array do
+        def each
+          super do |i|
+            yield 2 * i
+          end
+        end
+      end
+    }
+    a = [1, 2, 3]
+    assert_equal(1, m2.module_eval { a.min })
+  end
+
+  def test_module_inclusion
+    m1 = Module.new {
+      def foo
+        "m1#foo"
+      end
+
+      def bar
+        "m1#bar"
+      end
+    }
+    m2 = Module.new {
+      def bar
+        "m2#bar"
+      end
+
+      def baz
+        "m2#baz"
+      end
+    }
+    m3 = Module.new {
+      def baz
+        "m3#baz"
+      end
+    }
+    include_proc = Proc.new {
+      include m3, m2
+    }
+    m = Module.new {
+      refine String do
+        include m1
+        module_eval(&include_proc)
+
+        def call_foo
+          foo
+        end
+
+        def call_bar
+          bar
+        end
+
+        def call_baz
+          baz
+        end
+      end
+
+      def self.call_foo(s)
+        s.foo
+      end
+
+      def self.call_bar(s)
+        s.bar
+      end
+
+      def self.call_baz(s)
+        s.baz
+      end
+    }
+    assert_equal("m1#foo", m.module_eval { "abc".foo })
+    assert_equal("m2#bar", m.module_eval { "abc".bar })
+    assert_equal("m3#baz", m.module_eval { "abc".baz })
+    assert_equal("m1#foo", m.module_eval { "abc".call_foo })
+    assert_equal("m2#bar", m.module_eval { "abc".call_bar })
+    assert_equal("m3#baz", m.module_eval { "abc".call_baz })
+    assert_equal("m1#foo", m.call_foo("abc"))
+    assert_equal("m2#bar", m.call_bar("abc"))
+    assert_equal("m3#baz", m.call_baz("abc"))
+  end
+end
+
diff --git a/vm.c b/vm.c
index b61d5bf..bf445c8 100644
--- a/vm.c
+++ b/vm.c
@@ -819,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
diff --git a/vm_eval.c b/vm_eval.c
index 2bca7db..0a7e7ab 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -372,7 +372,7 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
                          rb_id2name(mid), type, (void *)recv, flags, klass);
         }
     }
-    return rb_method_entry(klass, mid, defined_class_ptr);
+    return rb_method_entry_get_with_omod(Qnil, klass, mid, defined_class_ptr);
 }
 
 static inline int
@@ -1213,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);
@@ -1234,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 577f72f..6bb6f5b 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1091,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;
 }
@@ -1106,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) {
@@ -1116,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;
 }
@@ -1123,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) {
@@ -1139,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) {
@@ -1167,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)
 {
@@ -1174,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;
 
@@ -1213,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);
@@ -1238,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;
 
@@ -1252,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");
@@ -1727,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 b17bdcd..ad3f129 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -149,8 +149,17 @@ 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; \
diff --git a/vm_method.c b/vm_method.c
index f2afa30..815fd43 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,6 +15,7 @@ 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;
 };
@@ -393,15 +394,25 @@ rb_get_alloc_func(VALUE klass)
 }
 
 static rb_method_entry_t*
-search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
+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;
 	}
@@ -419,17 +430,18 @@ search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
  * rb_method_entry() simply.
  */
 rb_method_entry_t *
-rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *defined_class_ptr)
+rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *defined_class_ptr)
 {
-    VALUE defined_class;
+    VALUE iclass, defined_class;
     rb_method_entry_t *me;
 
-    me = search_method(klass, id, &defined_class);
+    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)) {
@@ -449,18 +461,33 @@ rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *defined_class_ptr)
 }
 
 rb_method_entry_t *
-rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
+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, defined_class_ptr);
+    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
@@ -552,9 +579,9 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
 	rb_secure(4);
     }
 
-    me = search_method(klass, name, &defined_class);
+    me = search_method(klass, name, Qnil, &defined_class);
     if (!me && TYPE(klass) == T_MODULE) {
-	me = search_method(rb_cObject, name, &defined_class);
+	me = search_method(rb_cObject, name, Qnil, &defined_class);
     }
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -640,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");
@@ -655,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, 0);
+    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";
@@ -678,6 +710,11 @@ rb_undef(VALUE klass, ID id)
 		      rb_id2name(id), s0, rb_class2name(c));
     }
 
+    if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
+	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);
@@ -939,11 +976,11 @@ rb_alias(VALUE klass, ID name, ID def)
     }
 
   again:
-    orig_me = search_method(klass, def, 0);
+    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, 0),
+	    (orig_me = search_method(rb_cObject, def, Qnil, 0),
 				     UNDEFINED_METHOD_ENTRY_P(orig_me))) {
 	    rb_print_undef(klass, def, 0);
 	}
@@ -1205,9 +1242,9 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
 
 	id = rb_to_id(argv[i]);
 	for (;;) {
-	    me = search_method(m, id, 0);
+	    me = search_method(m, id, Qnil, 0);
 	    if (me == 0) {
-		me = search_method(rb_cObject, id, 0);
+		me = search_method(rb_cObject, id, Qnil, 0);
 	    }
 	    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 		rb_print_undef(module, id, 0);
@@ -1313,6 +1350,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
