diff --git a/class.c b/class.c
index e083bf6..0aa7561 100644
--- a/class.c
+++ b/class.c
@@ -678,6 +678,13 @@ rb_include_module(VALUE klass, VALUE module)
 }
 
 static int
+add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
+{
+    rb_add_refined_method_entry((VALUE) data, (ID) key);
+    return ST_CONTINUE;
+}
+
+static int
 include_modules_at(VALUE klass, VALUE c, VALUE module)
 {
     VALUE p;
@@ -707,6 +714,13 @@ include_modules_at(VALUE klass, VALUE c, VALUE module)
 	    }
 	}
 	c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
+	if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
+	    VALUE refined_class =
+		rb_refinement_module_get_refined_class(klass);
+
+	    st_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i,
+		       (st_data_t) refined_class);
+	}
 	if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
 	    changed = 1;
       skip:
@@ -738,7 +752,7 @@ rb_prepend_module(VALUE klass, VALUE module)
 	RCLASS_SUPER(klass) = origin;
 	RCLASS_ORIGIN(klass) = origin;
 	RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
-	RCLASS_M_TBL(klass) = 0;
+	RCLASS_M_TBL(klass) = st_init_numtable();
     }
     changed = include_modules_at(klass, klass, module);
     if (changed < 0)
diff --git a/eval.c b/eval.c
index b90616d..fd8bf49 100644
--- a/eval.c
+++ b/eval.c
@@ -1184,6 +1184,14 @@ rb_mod_using(VALUE self, VALUE module)
     return self;
 }
 
+VALUE rb_refinement_module_get_refined_class(VALUE module)
+{
+    ID id_refined_class;
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    return rb_attr_get(module, id_refined_class);
+}
+
 static VALUE
 refinement_module_include(int argc, VALUE *argv, VALUE module)
 {
@@ -1192,11 +1200,9 @@ refinement_module_include(int argc, VALUE *argv, VALUE module)
     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);
+    klass = rb_refinement_module_get_refined_class(module);
     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->ep)) &&
diff --git a/gc.c b/gc.c
index 0265b8e..4da1177 100644
--- a/gc.c
+++ b/gc.c
@@ -2404,6 +2404,7 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
     const rb_method_definition_t *def = me->def;
 
     gc_mark(objspace, me->klass);
+  again:
     if (!def) return;
     switch (def->type) {
       case VM_METHOD_TYPE_ISEQ:
@@ -2416,6 +2417,9 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
       case VM_METHOD_TYPE_IVAR:
 	gc_mark(objspace, def->body.attr.location);
 	break;
+      case VM_METHOD_TYPE_REFINED:
+	def = def->body.orig_def;
+	goto again;
       default:
 	break; /* ignore */
     }
diff --git a/internal.h b/internal.h
index 1ea0ca9..423ce9b 100644
--- a/internal.h
+++ b/internal.h
@@ -98,6 +98,9 @@ NORETURN(void rb_async_bug_errno(const char *,int));
 const char *rb_builtin_type_name(int t);
 const char *rb_builtin_class_name(VALUE x);
 
+/* eval.c */
+VALUE rb_refinement_module_get_refined_class(VALUE module);
+
 /* eval_error.c */
 void ruby_error_print(void);
 VALUE rb_get_backtrace(VALUE info);
diff --git a/method.h b/method.h
index a87fc5c..57a409f 100644
--- a/method.h
+++ b/method.h
@@ -42,7 +42,8 @@ typedef enum {
     VM_METHOD_TYPE_NOTIMPLEMENTED,
     VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
     VM_METHOD_TYPE_MISSING,   /* wrapper for method_missing(id) */
-    VM_METHOD_TYPE_CFUNC_FRAMELESS
+    VM_METHOD_TYPE_CFUNC_FRAMELESS,
+    VM_METHOD_TYPE_REFINED,
 } rb_method_type_t;
 
 struct rb_call_info_struct;
@@ -72,6 +73,7 @@ typedef struct rb_method_definition_struct {
 	    OPTIMIZED_METHOD_TYPE_SEND,
 	    OPTIMIZED_METHOD_TYPE_CALL
 	} optimize_type;
+	struct rb_method_definition_struct *orig_def;
     } body;
     int alias_count;
 } rb_method_definition_t;
@@ -94,9 +96,16 @@ 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, VALUE *define_class_ptr);
-
-rb_method_entry_t *rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id, VALUE *define_class_ptr);
-rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id, VALUE *define_class_ptr);
+void rb_add_refined_method_entry(VALUE refined_class, ID mid);
+rb_method_entry_t *rb_resolve_refined_method(VALUE refinements,
+					     rb_method_entry_t *me,
+					     rb_method_entry_t *me_buf,
+					     VALUE *defined_class_ptr);
+rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id,
+						    rb_method_entry_t *me_buf,
+						    VALUE *defined_class_ptr);
+
+rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
 rb_method_entry_t *rb_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/object.c b/object.c
index f515d48..62db906 100644
--- a/object.c
+++ b/object.c
@@ -1337,7 +1337,7 @@ rb_obj_cmp(VALUE obj1, VALUE obj2)
 static VALUE
 rb_mod_to_s(VALUE klass)
 {
-    ID id_refined_class, id_defined_at;
+    ID id_defined_at;
     VALUE refined_class, defined_at;
 
     if (FL_TEST(klass, FL_SINGLETON)) {
@@ -1357,8 +1357,7 @@ rb_mod_to_s(VALUE klass)
 
 	return s;
     }
-    CONST_ID(id_refined_class, "__refined_class__");
-    refined_class = rb_attr_get(klass, id_refined_class);
+    refined_class = rb_refinement_module_get_refined_class(klass);
     if (!NIL_P(refined_class)) {
 	VALUE s = rb_usascii_str_new2("#<refinement:");
 
diff --git a/proc.c b/proc.c
index b387eb0..2af78cf 100644
--- a/proc.c
+++ b/proc.c
@@ -948,7 +948,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, &defined_class);
+    me = rb_method_entry_with_refinements(klass, id, &meb, &defined_class);
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	ID rmiss = rb_intern("respond_to_missing?");
 	VALUE sym = ID2SYM(id);
@@ -1713,6 +1713,8 @@ rb_method_entry_arity(const rb_method_entry_t *me)
 	  default:
 	    break;
 	}
+      case VM_METHOD_TYPE_REFINED:
+	return -1;
       }
     }
     rb_bug("rb_method_entry_arity: invalid method entry type (%d)", def->type);
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index 3ca00ed..3b8a0cd 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -726,7 +726,6 @@ class TestRefinement < Test::Unit::TestCase
   end
 
   def test_inline_method_cache
-    skip "can't implement efficiently with the current implementation of refinements"
     c = InlineMethodCache::C.new
     f = Proc.new { c.foo }
     assert_equal("original", f.call)
@@ -822,4 +821,31 @@ class TestRefinement < Test::Unit::TestCase
       end
     end
   end
+
+  module RedifineRefinedMethod
+    class C
+      def foo
+        "original"
+      end
+    end
+
+    module M
+      refine C do
+        def foo
+          "refined"
+        end
+      end
+    end
+
+    class C
+      def foo
+        "redefined"
+      end
+    end
+  end
+
+  def test_redefine_refined_method
+    c = RedifineRefinedMethod::C.new
+    assert_equal("refined", RedifineRefinedMethod::M.module_eval { c.foo })
+  end
 end
diff --git a/vm_eval.c b/vm_eval.c
index e957832..ee82cbc 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -179,7 +179,17 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
       case VM_METHOD_TYPE_BMETHOD:
 	return vm_call_bmethod_body(th, ci, argv);
       case VM_METHOD_TYPE_ZSUPER:
+      case VM_METHOD_TYPE_REFINED:
 	{
+	    if (ci->me->def->type == VM_METHOD_TYPE_REFINED &&
+		ci->me->def->body.orig_def) {
+		rb_method_entry_t orig_me;
+		orig_me = *ci->me;
+		orig_me.def = ci->me->def->body.orig_def;
+		ci->me = &orig_me;
+		goto again;
+	    }
+
 	    ci->defined_class = RCLASS_SUPER(ci->defined_class);
 
 	    if (!ci->defined_class || !(ci->me = rb_method_entry(ci->defined_class, ci->mid, &ci->defined_class))) {
@@ -274,8 +284,7 @@ stack_check(void)
 }
 
 static inline rb_method_entry_t *
-    rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
-			   VALUE *defined_class_ptr);
+    rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
 static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self);
 #define NOEX_OK NOEX_NOSUPER
 
@@ -295,11 +304,11 @@ static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t
  */
 static inline VALUE
 rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
-	 call_type scope, VALUE self, VALUE refinements)
+	 call_type scope, VALUE self)
 {
     VALUE defined_class;
     rb_method_entry_t *me =
-	rb_search_method_entry(refinements, recv, mid, &defined_class);
+	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);
 
@@ -363,7 +372,7 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
 	}
     }
 
-    me = rb_search_method_entry(Qnil, recv, mid, &defined_class);
+    me = rb_search_method_entry(recv, mid, &defined_class);
     call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
     if (call_status != NOEX_OK) {
 	if (rb_method_basic_definition_p(klass, idMethodMissing)) {
@@ -428,8 +437,7 @@ rb_type_str(enum ruby_value_type type)
 }
 
 static inline rb_method_entry_t *
-rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
-		       VALUE *defined_class_ptr)
+rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
 {
     VALUE klass = CLASS_OF(recv);
 
@@ -468,8 +476,7 @@ rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
                          rb_id2name(mid), type, (void *)recv, flags, klass);
         }
     }
-    return rb_method_entry_get_with_refinements(refinements, klass, mid,
-						defined_class_ptr);
+    return rb_method_entry(klass, mid, defined_class_ptr);
 }
 
 static inline int
@@ -533,7 +540,7 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc
 static inline VALUE
 rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope)
 {
-    return rb_call0(recv, mid, argc, argv, scope, Qundef, Qnil);
+    return rb_call0(recv, mid, argc, argv, scope, Qundef);
 }
 
 NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv,
@@ -786,10 +793,24 @@ rb_funcall_passing_block_with_refinements(VALUE recv, ID mid, int argc,
 					  const VALUE *argv,
 					  VALUE refinements)
 {
-    PASS_PASSED_BLOCK_TH(GET_THREAD());
+    VALUE defined_class;
+    rb_method_entry_t meb, *me =
+	rb_search_method_entry(recv, mid, &defined_class);
+    rb_thread_t *th;
+    int call_status;
 
-    return rb_call0(recv, mid, argc, argv, CALL_PUBLIC, Qundef,
-		    refinements);
+    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
+	me = rb_resolve_refined_method(refinements, me, &meb,
+				       &defined_class);
+    }
+    PASS_PASSED_BLOCK_TH(GET_THREAD());
+    th = GET_THREAD();
+    call_status = rb_method_call_status(th, me, CALL_PUBLIC, Qundef);
+    if (call_status != NOEX_OK) {
+	return method_missing(recv, mid, argc, argv, call_status);
+    }
+    stack_check();
+    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 }
 
 static VALUE
@@ -816,7 +837,7 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
 	id = rb_to_id(vid);
     }
     PASS_PASSED_BLOCK_TH(th);
-    return rb_call0(recv, id, argc, argv, scope, self, Qnil);
+    return rb_call0(recv, id, argc, argv, scope, self);
 }
 
 /*
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index bf524d6..9e75552 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1693,6 +1693,47 @@ vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
     return vm_call_method(th, reg_cfp, &ci_entry);
 }
 
+static VALUE
+copy_refinement_iclass(VALUE iclass, VALUE superclass)
+{
+    VALUE result, c;
+
+    Check_Type(iclass, T_ICLASS);
+    c = result = rb_include_class_new(RBASIC(iclass)->klass, superclass);
+    RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
+    iclass = RCLASS_SUPER(iclass);
+    while (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
+	c = RCLASS_SUPER(c) = rb_include_class_new(RBASIC(iclass)->klass,
+						   RCLASS_SUPER(c));
+	RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
+	iclass = RCLASS_SUPER(iclass);
+    }
+    return result;
+}
+
+static VALUE
+find_refinement(VALUE refinements, VALUE klass)
+{
+    VALUE refinement;
+
+    if (NIL_P(refinements)) {
+	return Qnil;
+    }
+    refinement = rb_hash_lookup(refinements, klass);
+    if (NIL_P(refinement) &&
+	BUILTIN_TYPE(klass) == T_ICLASS) {
+	refinement = rb_hash_lookup(refinements,
+				    RBASIC(klass)->klass);
+	if (!NIL_P(refinement)) {
+	    refinement = copy_refinement_iclass(refinement, klass);
+	}
+    }
+    return refinement;
+}
+
+static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
+static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci);
+
 static inline VALUE
 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 {
@@ -1733,8 +1774,12 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 		return vm_call_bmethod(th, cfp, ci);
 	      }
 	      case VM_METHOD_TYPE_ZSUPER:{
-		VALUE klass = RCLASS_SUPER(ci->me->klass);
-		rb_call_info_t cie = *ci;
+		VALUE klass;
+		rb_call_info_t cie;
+
+	      zsuper_method_dispatch:
+		klass = RCLASS_SUPER(ci->me->klass);
+		cie = *ci;
 		ci = &cie;
 
 		ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
@@ -1776,6 +1821,44 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
 		break;
 	      case VM_METHOD_TYPE_UNDEF:
 		break;
+	      case VM_METHOD_TYPE_REFINED:{
+		NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep);
+		VALUE refinements = cref ? cref->nd_refinements : Qnil;
+		VALUE refinement, defined_class;
+		rb_method_entry_t orig_me, *me;
+		rb_call_info_t cie = *ci;
+		ci = &cie;
+
+		refinement = find_refinement(refinements,
+					     ci->defined_class);
+		if (NIL_P(refinement)) {
+		    goto no_refinement_dispatch;
+		}
+		me = rb_method_entry(refinement, ci->mid, &defined_class);
+		if (me) {
+		    if (ci->call == vm_call_super_method &&
+			cfp->me &&
+			rb_method_definition_eq(me->def, cfp->me->def)) {
+			goto no_refinement_dispatch;
+		    }
+		    ci->me = me;
+		    ci->defined_class = defined_class;
+		    if (me->def->type != VM_METHOD_TYPE_REFINED) {
+			goto normal_method_dispatch;
+		    }
+		}
+
+	      no_refinement_dispatch:
+		if (ci->me->def->body.orig_def) {
+		    orig_me = *ci->me;
+		    orig_me.def = ci->me->def->body.orig_def;
+		    ci->me = &orig_me;
+		    goto normal_method_dispatch;
+		}
+		else {
+		    goto zsuper_method_dispatch;
+		}
+	      }
 	    }
 	    rb_bug("vm_call_method: unsupported method type (%d)", ci->me->def->type);
 	}
@@ -1839,6 +1922,12 @@ vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
     return vm_call_method(th, reg_cfp, ci);
 }
 
+static VALUE
+vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
+{
+    return vm_call_method(th, reg_cfp, ci);
+}
+
 /* super */
 
 static inline VALUE
@@ -1927,7 +2016,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
 
     /* TODO: use inline cache */
     ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
-    ci->call = vm_call_general;
+    ci->call = vm_call_super_method;
 
     while (iseq && !iseq->klass) {
 	iseq = iseq->parent_iseq;
@@ -1935,7 +2024,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
 
     if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) {
 	ci->klass = RCLASS_SUPER(ci->defined_class);
-	ci->me = rb_method_entry_get_with_refinements(Qnil, ci->klass, ci->mid, &ci->defined_class);
+	ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
     }
 }
 
diff --git a/vm_method.c b/vm_method.c
index 6580bb6..ec54c2f 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -4,7 +4,7 @@
 
 #define CACHE_SIZE 0x800
 #define CACHE_MASK 0x7ff
-#define EXPR1(c,o,m) ((((c)>>3)^((o)>>3)^(m))&CACHE_MASK)
+#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
 
 #define NOEX_NOREDEF 0
 #ifndef NOEX_NOREDEF
@@ -21,7 +21,6 @@ struct cache_entry {		/* method hash table. */
     VALUE filled_version;        /* filled state version */
     ID mid;			/* method's id */
     VALUE klass;		/* receiver's class */
-    VALUE refinements;		/* refinements */
     rb_method_entry_t *me;
     VALUE defined_class;
 };
@@ -155,6 +154,12 @@ rb_free_method_entry(rb_method_entry_t *me)
 
     if (def) {
 	if (def->alias_count == 0) {
+	    if (def->type == VM_METHOD_TYPE_REFINED) {
+		def->body.orig_def->alias_count--;
+		if (def->body.orig_def->alias_count == 0) {
+		    xfree(def->body.orig_def);
+		}
+	    }
 	    xfree(def);
 	}
 	else if (def->alias_count > 0) {
@@ -167,7 +172,50 @@ rb_free_method_entry(rb_method_entry_t *me)
 
 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
 
-void rb_redefine_opt_method(VALUE, ID);
+static inline rb_method_entry_t *
+lookup_method_table(VALUE klass, ID id)
+{
+    st_data_t body;
+    st_table *m_tbl = RCLASS_M_TBL(klass);
+    if (st_lookup(m_tbl, id, &body)) {
+	return (rb_method_entry_t *) body;
+    }
+    else {
+	return 0;
+    }
+}
+
+static void
+make_method_entry_refined(rb_method_entry_t *me)
+{
+    rb_method_definition_t *new_def;
+
+    if (me->def && me->def->type == VM_METHOD_TYPE_REFINED)
+	return;
+
+    new_def = ALLOC(rb_method_definition_t);
+    new_def->type = VM_METHOD_TYPE_REFINED;
+    new_def->original_id = me->called_id;
+    new_def->alias_count = 0;
+    new_def->body.orig_def = me->def;
+    rb_vm_check_redefinition_opt_method(me, me->klass);
+    if (me->def) me->def->alias_count++;
+    me->def = new_def;
+}
+
+void
+rb_add_refined_method_entry(VALUE refined_class, ID mid)
+{
+    rb_method_entry_t *me = lookup_method_table(refined_class, mid);
+
+    if (me) {
+	make_method_entry_refined(me);
+    }
+    else {
+	rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0,
+		      NOEX_PUBLIC);
+    }
+}
 
 static rb_method_entry_t *
 rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
@@ -179,6 +227,7 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
 #endif
     st_table *mtbl;
     st_data_t data;
+    int make_refined = 0;
 
     if (NIL_P(klass)) {
 	klass = rb_cObject;
@@ -199,14 +248,19 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
     rklass = klass;
 #endif
     if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
-	ID id_refined_class;
-	VALUE refined_class;
+	VALUE refined_class =
+	    rb_refinement_module_get_refined_class(klass);
 
-	CONST_ID(id_refined_class, "__refined_class__");
-	refined_class = rb_ivar_get(klass, id_refined_class);
-	rb_redefine_opt_method(refined_class, mid);
+	rb_add_refined_method_entry(refined_class, mid);
+    }
+    if (type == VM_METHOD_TYPE_REFINED) {
+	rb_method_entry_t *old_me =
+	    lookup_method_table(RCLASS_ORIGIN(klass), mid);
+	if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
+    }
+    else {
+	klass = RCLASS_ORIGIN(klass);
     }
-    klass = RCLASS_ORIGIN(klass);
     mtbl = RCLASS_M_TBL(klass);
 
     /* check re-definition */
@@ -222,6 +276,8 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
 	}
 #endif
 	rb_vm_check_redefinition_opt_method(old_me, klass);
+	if (old_def->type == VM_METHOD_TYPE_REFINED)
+	    make_refined = 1;
 
 	if (RTEST(ruby_verbose) &&
 	    type != VM_METHOD_TYPE_UNDEF &&
@@ -274,6 +330,10 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
 	}
     }
 
+    if (make_refined) {
+	make_method_entry_refined(me);
+    }
+
     st_insert(mtbl, mid, (st_data_t) me);
 
     return me;
@@ -341,7 +401,12 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
     int line;
     rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex);
     rb_method_definition_t *def = ALLOC(rb_method_definition_t);
-    me->def = def;
+    if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
+	me->def->body.orig_def = def;
+    }
+    else {
+	me->def = def;
+    }
     def->type = type;
     def->original_id = mid;
     def->alias_count = 0;
@@ -379,10 +444,13 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
       case VM_METHOD_TYPE_ZSUPER:
       case VM_METHOD_TYPE_UNDEF:
 	break;
+      case VM_METHOD_TYPE_REFINED:
+	def->body.orig_def = (rb_method_definition_t *) opts;
+	break;
       default:
 	rb_bug("rb_add_method: unsupported method type (%d)\n", type);
     }
-    if (type != VM_METHOD_TYPE_UNDEF) {
+    if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
 	method_added(klass, mid);
     }
     return me;
@@ -425,42 +493,14 @@ rb_get_alloc_func(VALUE klass)
     return 0;
 }
 
-static VALUE
-copy_refinement_iclass(VALUE iclass, VALUE superclass)
-{
-    VALUE result, c;
-
-    Check_Type(iclass, T_ICLASS);
-    c = result = rb_include_class_new(RBASIC(iclass)->klass, superclass);
-    RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
-    iclass = RCLASS_SUPER(iclass);
-    while (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
-	c = RCLASS_SUPER(c) = rb_include_class_new(RBASIC(iclass)->klass,
-						   RCLASS_SUPER(c));
-	RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
-	iclass = RCLASS_SUPER(iclass);
-    }
-    return result;
-}
-
-static inline int
-lookup_method_table(VALUE klass, ID id, st_data_t *body)
-{
-    st_table *m_tbl = RCLASS_M_TBL(klass);
-    if (!m_tbl) {
-	m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(RBASIC(klass)->klass));
-    }
-    return st_lookup(m_tbl, id, body);
-}
-
 static inline rb_method_entry_t*
 search_method_with_refinements(VALUE klass, ID id, VALUE refinements,
 			       VALUE *defined_class_ptr)
 {
-    st_data_t body;
+    rb_method_entry_t *me;
     VALUE iclass, skipped_class = Qnil;
 
-    for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
+    for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
 	if (klass != skipped_class) {
 	    iclass = rb_hash_lookup(refinements, klass);
 	    if (NIL_P(iclass) && BUILTIN_TYPE(klass) == T_ICLASS) {
@@ -473,38 +513,26 @@ search_method_with_refinements(VALUE klass, ID id, VALUE refinements,
 		klass = iclass;
 	    }
 	}
-	if (lookup_method_table(klass, id, &body)) break;
+	if ((me = lookup_method_table(klass, id)) != 0) break;
     }
 
     if (defined_class_ptr)
 	*defined_class_ptr = klass;
-    return (rb_method_entry_t *)body;
+    return me;
 }
 
 static inline rb_method_entry_t*
-search_method_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
+search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
-    st_data_t body;
+    rb_method_entry_t *me;
 
-    for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
-	if (lookup_method_table(klass, id, &body)) break;
+    for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
+	if ((me = lookup_method_table(klass, id)) != 0) break;
     }
 
     if (defined_class_ptr)
 	*defined_class_ptr = klass;
-    return (rb_method_entry_t *)body;
-}
-
-static rb_method_entry_t*
-search_method(VALUE klass, ID id, VALUE refinements, VALUE *defined_class_ptr)
-{
-    if (NIL_P(refinements)) {
-	return search_method_without_refinements(klass, id, defined_class_ptr);
-    }
-    else {
-	return search_method_with_refinements(klass, id, refinements,
-					      defined_class_ptr);
-    }
+    return me;
 }
 
 /*
@@ -514,19 +542,17 @@ search_method(VALUE klass, ID id, VALUE refinements, VALUE *defined_class_ptr)
  * rb_method_entry() simply.
  */
 rb_method_entry_t *
-rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id,
+rb_method_entry_get_without_cache(VALUE klass, ID id,
 				  VALUE *defined_class_ptr)
 {
     VALUE defined_class;
-    rb_method_entry_t *me = search_method(klass, id, refinements,
-					  &defined_class);
+    rb_method_entry_t *me = search_method(klass, id, &defined_class);
 
     if (ruby_running) {
 	struct cache_entry *ent;
-	ent = cache + EXPR1(klass, refinements, id);
+	ent = cache + EXPR1(klass, id);
 	ent->filled_version = GET_VM_STATE_VERSION();
 	ent->klass = klass;
-	ent->refinements = refinements;
 	ent->defined_class = defined_class;
 
 	if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -546,37 +572,89 @@ rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id,
 }
 
 rb_method_entry_t *
-rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id,
-				     VALUE *defined_class_ptr)
+rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
 #if OPT_GLOBAL_METHOD_CACHE
     struct cache_entry *ent;
 
-    ent = cache + EXPR1(klass, refinements, id);
+    ent = cache + EXPR1(klass, id);
     if (ent->filled_version == GET_VM_STATE_VERSION() &&
-	ent->mid == id && ent->klass == klass &&
-       	ent->refinements == refinements) {
+	ent->mid == id && ent->klass == klass) {
 	if (defined_class_ptr)
 	    *defined_class_ptr = ent->defined_class;
 	return ent->me;
     }
 #endif
 
-    return rb_method_entry_get_without_cache(klass, refinements, id,
+    return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
+}
+
+static rb_method_entry_t *
+get_original_method_entry(VALUE refinements,
+			  rb_method_entry_t *me, rb_method_entry_t *me_buf,
+			  VALUE *defined_class_ptr)
+{
+    if (me->def->body.orig_def) {
+	*me_buf = *me;
+	me_buf->def = me->def->body.orig_def;
+	return me_buf;
+    }
+    else {
+	rb_method_entry_t *tmp_me;
+	tmp_me = rb_method_entry(RCLASS_SUPER(me->klass), me->called_id,
+				 defined_class_ptr);
+	return rb_resolve_refined_method(refinements, tmp_me, me_buf,
+					 defined_class_ptr);
+    }
+}
+
+rb_method_entry_t *
+rb_resolve_refined_method(VALUE refinements, rb_method_entry_t *me,
+			  rb_method_entry_t *me_buf,
+			  VALUE *defined_class_ptr)
+{
+    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
+	VALUE refinement;
+	rb_method_entry_t *tmp_me;
+
+	refinement = find_refinement(refinements, me->klass);
+	if (NIL_P(refinement)) {
+	    return get_original_method_entry(refinements, me, me_buf,
+					     defined_class_ptr);
+	}
+	tmp_me = rb_method_entry(refinement, me->called_id,
+				 defined_class_ptr);
+	if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
+	    return tmp_me;
+	}
+	else {
+	    return get_original_method_entry(refinements, me, me_buf,
 					     defined_class_ptr);
+	}
+    }
+    else {
+	return me;
+    }
 }
 
 rb_method_entry_t *
-rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
+rb_method_entry_with_refinements(VALUE klass, ID id,
+				 rb_method_entry_t *me_buf,
+				 VALUE *defined_class_ptr)
 {
-    NODE *cref = rb_vm_cref();
-    VALUE refinements = Qnil;
+    VALUE defined_class;
+    rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
+
+    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
+	NODE *cref = rb_vm_cref();
+	VALUE refinements = cref ? cref->nd_refinements : Qnil;
 
-    if (cref && !NIL_P(cref->nd_refinements)) {
-	refinements = cref->nd_refinements;
+	me = rb_resolve_refined_method(refinements, me, me_buf,
+				       &defined_class);
     }
-    return rb_method_entry_get_with_refinements(refinements, klass, id,
-					       	defined_class_ptr);
+    if (defined_class_ptr)
+	*defined_class_ptr = defined_class;
+    return me;
 }
 
 static void
@@ -675,9 +753,9 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
 	rb_secure(4);
     }
 
-    me = search_method(klass, name, Qnil, &defined_class);
+    me = search_method(klass, name, &defined_class);
     if (!me && RB_TYPE_P(klass, T_MODULE)) {
-	me = search_method(rb_cObject, name, Qnil, &defined_class);
+	me = search_method(rb_cObject, name, &defined_class);
     }
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -699,7 +777,9 @@ 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, 0);
+    rb_method_entry_t meb;
+    rb_method_entry_t *me =
+	rb_method_entry_with_refinements(klass, id, &meb, 0);
 
     if (me != 0) {
 	if ((ex & ~NOEX_RESPONDS) &&
@@ -765,9 +845,6 @@ void
 rb_undef(VALUE klass, ID id)
 {
     rb_method_entry_t *me;
-    NODE *cref = rb_vm_cref();
-    VALUE refinements = Qnil;
-    void rb_using_refinement(NODE *cref, VALUE klass, VALUE module);
 
     if (NIL_P(klass)) {
 	rb_raise(rb_eTypeError, "no class to undef method");
@@ -783,10 +860,7 @@ rb_undef(VALUE klass, ID id)
 	rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
     }
 
-    if (cref && !NIL_P(cref->nd_refinements)) {
-	refinements = cref->nd_refinements;
-    }
-    me = search_method(klass, id, refinements, 0);
+    me = search_method(klass, id, 0);
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	const char *s0 = " class";
@@ -807,11 +881,6 @@ 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_using_refinement(cref, klass, mod);
-	klass = mod;
-    }
     rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
 
     CALL_METHOD_HOOK(klass, undefined, id);
@@ -1033,6 +1102,10 @@ rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
 static int
 rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
 {
+    if (d1 && d1->type == VM_METHOD_TYPE_REFINED)
+	d1 = d1->body.orig_def;
+    if (d2 && d2->type == VM_METHOD_TYPE_REFINED)
+	d2 = d2->body.orig_def;
     if (d1 == d2) return 1;
     if (!d1 || !d2) return 0;
     if (d1->type != d2->type) {
@@ -1067,6 +1140,7 @@ rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_defini
 static st_index_t
 rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
 {
+  again:
     hash = rb_hash_uint(hash, def->type);
     switch (def->type) {
       case VM_METHOD_TYPE_ISEQ:
@@ -1087,6 +1161,9 @@ rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
 	return hash;
       case VM_METHOD_TYPE_OPTIMIZED:
 	return rb_hash_uint(hash, def->body.optimize_type);
+      case VM_METHOD_TYPE_REFINED:
+	def = def->body.orig_def;
+	goto again;
       default:
 	rb_bug("rb_hash_method_definition: unsupported method type (%d)\n", def->type);
     }
@@ -1116,11 +1193,11 @@ rb_alias(VALUE klass, ID name, ID def)
     }
 
   again:
-    orig_me = search_method(klass, def, Qnil, 0);
+    orig_me = search_method(klass, def, 0);
 
     if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
 	if ((!RB_TYPE_P(klass, T_MODULE)) ||
-	    (orig_me = search_method(rb_cObject, def, Qnil, 0),
+	    (orig_me = search_method(rb_cObject, def, 0),
 	     UNDEFINED_METHOD_ENTRY_P(orig_me))) {
 	    rb_print_undef(klass, def, 0);
 	}
@@ -1396,9 +1473,9 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
 
 	id = rb_to_id(argv[i]);
 	for (;;) {
-	    me = search_method(m, id, Qnil, 0);
+	    me = search_method(m, id, 0);
 	    if (me == 0) {
-		me = search_method(rb_cObject, id, Qnil, 0);
+		me = search_method(rb_cObject, id, 0);
 	    }
 	    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 		rb_print_undef(module, id, 0);
@@ -1512,21 +1589,6 @@ obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
 }
 
 void
-rb_redefine_opt_method(VALUE klass, ID mid)
-{
-    st_data_t data;
-    rb_method_entry_t *me = 0;
-    VALUE origin = RCLASS_ORIGIN(klass);
-
-    if (!st_lookup(RCLASS_M_TBL(origin), 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, origin);
-}
-
-void
 Init_eval_method(void)
 {
 #undef rb_intern
