Index: EcnlProtoTool/trunk/mruby-2.1.1/src/class.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/src/class.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/src/class.c	(revision 439)
@@ -8,4 +8,5 @@
 #include <mruby.h>
 #include <mruby/array.h>
+#include <mruby/hash.h>
 #include <mruby/class.h>
 #include <mruby/numeric.h>
@@ -16,6 +17,7 @@
 #include <mruby/data.h>
 #include <mruby/istruct.h>
-
-KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
+#include <mruby/opcode.h>
+
+KHASH_DEFINE(mt, mrb_sym, mrb_method_t, TRUE, kh_int_hash_func, kh_int_hash_equal)
 
 void
@@ -28,7 +30,9 @@
   for (k = kh_begin(h); k != kh_end(h); k++) {
     if (kh_exist(h, k)) {
-      struct RProc *m = kh_value(h, k);
-      if (m) {
-        mrb_gc_mark(mrb, (struct RBasic*)m);
+      mrb_method_t m = kh_value(h, k);
+
+      if (MRB_METHOD_PROC_P(m)) {
+        struct RProc *p = MRB_METHOD_PROC(m);
+        mrb_gc_mark(mrb, (struct RBasic*)p);
       }
     }
@@ -51,9 +55,38 @@
 }
 
-static void
-name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
-{
-  mrb_obj_iv_set(mrb, (struct RObject*)c,
-                 mrb_intern_lit(mrb, "__classid__"), mrb_symbol_value(name));
+void
+mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id)
+{
+  mrb_value name;
+  mrb_sym nsym = mrb_intern_lit(mrb, "__classname__");
+
+  if (mrb_obj_iv_defined(mrb, (struct RObject*)c, nsym)) return;
+  if (outer == NULL || outer == mrb->object_class) {
+    name = mrb_symbol_value(id);
+  }
+  else {
+    name = mrb_class_path(mrb, outer);
+    if (mrb_nil_p(name)) {      /* unnamed outer class */
+      if (outer != mrb->object_class && outer != c) {
+        mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"),
+                             mrb_obj_value(outer));
+      }
+      return;
+    }
+    else {
+      mrb_int len;
+      const char *n = mrb_sym_name_len(mrb, id, &len);
+
+      mrb_str_cat_lit(mrb, name, "::");
+      mrb_str_cat(mrb, name, n, len);
+    }
+  }
+  mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name);
+}
+
+mrb_bool
+mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len)
+{
+  return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1);
 }
 
@@ -61,10 +94,6 @@
 setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id)
 {
-  name_class(mrb, c, id);
+  mrb_class_name_class(mrb, outer, c, id);
   mrb_obj_iv_set(mrb, (struct RObject*)outer, id, mrb_obj_value(c));
-  if (outer != mrb->object_class) {
-    mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"),
-                   mrb_obj_value(outer));
-  }
 }
 
@@ -78,4 +107,5 @@
   if (o->c->tt == MRB_TT_SCLASS) return;
   sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
+  sc->flags |= MRB_FL_CLASS_IS_INHERITED;
   sc->mt = kh_init(mt, mrb);
   sc->iv = 0;
@@ -104,7 +134,21 @@
   mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
   mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o));
-}
-
-static struct RClass *
+  sc->flags |= o->flags & MRB_FL_OBJ_IS_FROZEN;
+}
+
+static mrb_value
+class_name_str(mrb_state *mrb, struct RClass* c)
+{
+  mrb_value path = mrb_class_path(mrb, c);
+  if (mrb_nil_p(path)) {
+    path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#<Module:") :
+                                    mrb_str_new_lit(mrb, "#<Class:");
+    mrb_str_cat_str(mrb, path, mrb_ptr_to_str(mrb, c));
+    mrb_str_cat_lit(mrb, path, ">");
+  }
+  return path;
+}
+
+static struct RClass*
 class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
 {
@@ -115,5 +159,5 @@
 }
 
-static struct RClass *
+static struct RClass*
 module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
 {
@@ -137,30 +181,9 @@
 }
 
-MRB_API struct RClass*
-mrb_class_outer_module(mrb_state *mrb, struct RClass *c)
-{
-  mrb_value outer;
-  struct RClass *cls;
-
-  outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
-  if (mrb_nil_p(outer)) return NULL;
-  cls = mrb_class_ptr(outer);
-  if (cls->tt == MRB_TT_SCLASS)
-  {
-    mrb_value klass;
-    klass = mrb_obj_iv_get(mrb, (struct RObject *)cls,
-                           mrb_intern_lit(mrb, "__attached__"));
-    if (class_ptr_p(klass)) {
-      cls = mrb_class_ptr(klass);
-    }
-  }
-  return cls;
-}
-
 static void
 check_if_class_or_module(mrb_state *mrb, mrb_value obj)
 {
   if (!class_ptr_p(obj)) {
-    mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj));
+    mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class/module", obj);
   }
 }
@@ -192,5 +215,5 @@
 }
 
-MRB_API struct RClass*
+struct RClass*
 mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
 {
@@ -199,6 +222,6 @@
     mrb_value old = mrb_const_get(mrb, outer, id);
 
-    if (mrb_type(old) != MRB_TT_MODULE) {
-      mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old));
+    if (!mrb_module_p(old)) {
+      mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old);
     }
     return mrb_class_ptr(old);
@@ -233,7 +256,6 @@
     MRB_CLASS_ORIGIN(c);
     if (super && mrb_class_real(c->super) != super) {
-      mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
-                 mrb_sym2str(mrb, name),
-                 mrb_obj_value(c->super), mrb_obj_value(super));
+      mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %n (%C not %C)",
+                 name, c->super, super);
     }
     return c;
@@ -250,5 +272,5 @@
 {
   if (!super) {
-    mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name));
+    mrb_warn(mrb, "no super class for '%n', Object assumed", name);
   }
   return define_class(mrb, name, super, mrb->object_class);
@@ -261,5 +283,12 @@
 }
 
-static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value cv);
+static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value);
+#ifdef MRB_METHOD_CACHE
+static void mc_clear_all(mrb_state *mrb);
+static void mc_clear_by_id(mrb_state *mrb, struct RClass*, mrb_sym);
+#else
+#define mc_clear_all(mrb)
+#define mc_clear_by_id(mrb,c,s)
+#endif
 
 static void
@@ -271,13 +300,15 @@
   if (!super)
     super = mrb->object_class;
+  super->flags |= MRB_FL_CLASS_IS_INHERITED;
   s = mrb_obj_value(super);
+  mrb_mc_clear_by_class(mrb, klass);
   mid = mrb_intern_lit(mrb, "inherited");
   if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) {
     mrb_value c = mrb_obj_value(klass);
-    mrb_funcall_argv(mrb, mrb_obj_value(super), mid, 1, &c);
-  }
-}
-
-MRB_API struct RClass*
+    mrb_funcall_argv(mrb, s, mid, 1, &c);
+  }
+}
+
+struct RClass*
 mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
 {
@@ -286,7 +317,6 @@
 
   if (!mrb_nil_p(super)) {
-    if (mrb_type(super) != MRB_TT_CLASS) {
-      mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)",
-                 mrb_inspect(mrb, super));
+    if (!mrb_class_p(super)) {
+      mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super);
     }
     s = mrb_class_ptr(super);
@@ -299,6 +329,6 @@
     mrb_value old = mrb_const_get(mrb, outer, id);
 
-    if (mrb_type(old) != MRB_TT_CLASS) {
-      mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old));
+    if (!mrb_class_p(old)) {
+      mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class", old);
     }
     c = mrb_class_ptr(old);
@@ -306,5 +336,5 @@
       /* check super class */
       if (mrb_class_real(c->super) != s) {
-        mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old);
+        mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %v", old);
       }
     }
@@ -337,5 +367,5 @@
 }
 
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
 {
@@ -343,5 +373,5 @@
 }
 
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_class_get(mrb_state *mrb, const char *name)
 {
@@ -349,5 +379,5 @@
 }
 
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_exc_get(mrb_state *mrb, const char *name)
 {
@@ -356,5 +386,5 @@
                               mrb_intern_cstr(mrb, name));
 
-  if (mrb_type(c) != MRB_TT_CLASS) {
+  if (!mrb_class_p(c)) {
     mrb_raise(mrb, mrb->eException_class, "exception corrupted");
   }
@@ -369,5 +399,5 @@
 }
 
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
 {
@@ -375,5 +405,5 @@
 }
 
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_module_get(mrb_state *mrb, const char *name)
 {
@@ -384,5 +414,5 @@
  * Defines a class under the namespace of \a outer.
  * \param outer  a class which contains the new class.
- * \param id     name of the new class
+ * \param name     name of the new class
  * \param super  a class from which the new class will derive.
  *               NULL means \c Object class.
@@ -397,5 +427,5 @@
  *       \a super, the function just returns the defined class.
  */
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super)
 {
@@ -405,6 +435,5 @@
 #if 0
   if (!super) {
-    mrb_warn(mrb, "no super class for '%S::%S', Object assumed",
-             mrb_obj_value(outer), mrb_sym2str(mrb, id));
+    mrb_warn(mrb, "no super class for '%C::%n', Object assumed", outer, id);
   }
 #endif
@@ -415,5 +444,5 @@
 
 MRB_API void
-mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p)
+mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_t m)
 {
   khash_t(mt) *h;
@@ -422,17 +451,19 @@
   h = c->mt;
 
-  if (MRB_FROZEN_P(c)) {
-    if (c->tt == MRB_TT_MODULE)
-      mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module");
-    else
-      mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class");
-  }
+  mrb_check_frozen(mrb, c);
   if (!h) h = c->mt = kh_init(mt, mrb);
   k = kh_put(mt, mrb, h, mid);
-  kh_value(h, k) = p;
-  if (p) {
+  kh_value(h, k) = m;
+  if (MRB_METHOD_PROC_P(m) && !MRB_METHOD_UNDEF_P(m)) {
+    struct RProc *p = MRB_METHOD_PROC(m);
+
+    p->flags |= MRB_PROC_SCOPE;
     p->c = NULL;
-    mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
-  }
+    mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)p);
+    if (!MRB_PROC_ENV_P(p)) {
+      MRB_PROC_SET_TARGET_CLASS(p, c);
+    }
+  }
+  mc_clear_by_id(mrb, c, mid);
 }
 
@@ -440,10 +471,12 @@
 mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec)
 {
-  struct RProc *p;
+  mrb_method_t m;
   int ai = mrb_gc_arena_save(mrb);
 
-  p = mrb_proc_new_cfunc(mrb, func);
-  p->target_class = c;
-  mrb_define_method_raw(mrb, c, mid, p);
+  MRB_METHOD_FROM_FUNC(m, func);
+  if (aspec == MRB_ARGS_NONE()) {
+    MRB_METHOD_NOARG_SET(m);
+  }
+  mrb_define_method_raw(mrb, c, mid, m);
   mrb_gc_arena_restore(mrb, ai);
 }
@@ -459,13 +492,8 @@
 mrb_notimplement(mrb_state *mrb)
 {
-  const char *str;
-  mrb_int len;
   mrb_callinfo *ci = mrb->c->ci;
 
   if (ci->mid) {
-    str = mrb_sym2name_len(mrb, ci->mid, &len);
-    mrb_raisef(mrb, E_NOTIMP_ERROR,
-      "%S() function is unimplemented on this machine",
-      mrb_str_new_static(mrb, str, (size_t)len));
+    mrb_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid);
   }
 }
@@ -481,25 +509,8 @@
 
 static mrb_value
-check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m)
-{
-  mrb_value tmp;
-
-  tmp = mrb_check_convert_type(mrb, val, t, c, m);
-  if (mrb_nil_p(tmp)) {
-    mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c));
-  }
-  return tmp;
-}
-
-static mrb_value
-to_str(mrb_state *mrb, mrb_value val)
-{
-  return check_type(mrb, val, MRB_TT_STRING, "String", "to_str");
-}
-
-static mrb_value
 to_ary(mrb_state *mrb, mrb_value val)
 {
-  return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
+  mrb_check_type(mrb, val, MRB_TT_ARRAY);
+  return val;
 }
 
@@ -507,23 +518,37 @@
 to_hash(mrb_state *mrb, mrb_value val)
 {
-  return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash");
-}
-
-static mrb_sym
-to_sym(mrb_state *mrb, mrb_value ss)
-{
-  if (mrb_type(ss) == MRB_TT_SYMBOL) {
-    return mrb_symbol(ss);
-  }
-  else if (mrb_string_p(ss)) {
-    return mrb_intern_str(mrb, to_str(mrb, ss));
-  }
-  else {
-    mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0);
-    mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
-    /* not reached */
-    return 0;
-  }
-}
+  mrb_check_type(mrb, val, MRB_TT_HASH);
+  return val;
+}
+
+#define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss)
+
+MRB_API mrb_int
+mrb_get_argc(mrb_state *mrb)
+{
+  mrb_int argc = mrb->c->ci->argc;
+
+  if (argc < 0) {
+    struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
+
+    argc = ARY_LEN(a);
+  }
+  return argc;
+}
+
+MRB_API mrb_value*
+mrb_get_argv(mrb_state *mrb)
+{
+  mrb_int argc = mrb->c->ci->argc;
+  mrb_value *array_argv = mrb->c->stack + 1;
+  if (argc < 0) {
+    struct RArray *a = mrb_ary_ptr(*array_argv);
+
+    array_argv = ARY_PTR(a);
+  }
+  return array_argv;
+}
+
+void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
 
 /*
@@ -539,5 +564,5 @@
     ----------------------------------------------------------------------------------------------
     o:      Object         [mrb_value]
-    C:      class/module   [mrb_value]
+    C:      Class/Module   [mrb_value]
     S:      String         [mrb_value]            when ! follows, the value may be nil
     A:      Array          [mrb_value]            when ! follows, the value may be nil
@@ -546,44 +571,82 @@
     z:      String         [char*]                NUL terminated string; z! gives NULL for nil
     a:      Array          [mrb_value*,mrb_int]   Receive two arguments; a! gives (NULL,0) for nil
-    f:      Float          [mrb_float]
-    i:      Integer        [mrb_int]
-    b:      Boolean        [mrb_bool]
-    n:      Symbol         [mrb_sym]
-    d:      Data           [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
-    I:      Inline struct  [void*]
-    &:      Block          [mrb_value]
-    *:      rest argument  [mrb_value*,mrb_int]   Receive the rest of the arguments as an array.
-    |:      optional                              Next argument of '|' and later are optional.
-    ?:      optional given [mrb_bool]             true if preceding argument (optional) is given.
+    f:      Fixnum/Float   [mrb_float]
+    i:      Fixnum/Float   [mrb_int]
+    b:      boolean        [mrb_bool]
+    n:      String/Symbol  [mrb_sym]
+    d:      data           [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil
+    I:      inline struct  [void*]
+    &:      block          [mrb_value]            &! raises exception if no block given
+    *:      rest argument  [mrb_value*,mrb_int]   The rest of the arguments as an array; *! avoid copy of the stack
+    |:      optional                              Following arguments are optional
+    ?:      optional given [mrb_bool]             true if preceding argument (optional) is given
+    ':':    keyword args   [mrb_kwargs const]     Get keyword arguments
  */
 MRB_API mrb_int
 mrb_get_args(mrb_state *mrb, const char *format, ...)
 {
+  const char *fmt = format;
   char c;
-  int i = 0;
+  mrb_int i = 0;
   va_list ap;
-  int argc = mrb->c->ci->argc;
-  int arg_i = 0;
-  mrb_bool array_argv;
+  mrb_int argc = mrb->c->ci->argc;
+  mrb_value *array_argv = mrb->c->stack+1;
+  mrb_bool argv_on_stack = argc >= 0;
   mrb_bool opt = FALSE;
+  mrb_bool opt_skip = TRUE;
   mrb_bool given = TRUE;
-
+  mrb_value kdict;
+  mrb_bool reqkarg = FALSE;
+  mrb_int needargc = 0;
+
+  if (!argv_on_stack) {
+    struct RArray *a = mrb_ary_ptr(*array_argv);
+    array_argv = ARY_PTR(a);
+    argc = ARY_LEN(a);
+  }
   va_start(ap, format);
-  if (argc < 0) {
-    struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
-
-    argc = a->len;
-    array_argv = TRUE;
+
+#define ARGV array_argv
+
+  while ((c = *fmt++)) {
+    switch (c) {
+    case '|':
+      opt = TRUE;
+      break;
+    case '*':
+      opt_skip = FALSE;
+      if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE;
+      goto check_exit;
+    case '!':
+      break;
+    case ':':
+      reqkarg = TRUE;
+      /* fall through */
+    case '&': case '?':
+      if (opt) opt_skip = FALSE;
+      break;
+    default:
+      if (!opt) needargc ++;
+      break;
+    }
+  }
+
+ check_exit:
+  if (reqkarg && argc > needargc && mrb_hash_p(kdict = ARGV[argc - 1])) {
+    mrb_hash_check_kdict(mrb, kdict);
+    argc --;
   }
   else {
-    array_argv = FALSE;
-  }
-
-#define ARGV \
-  (array_argv ? mrb_ary_ptr(mrb->c->stack[1])->ptr : (mrb->c->stack + 1))
-
+    kdict = mrb_nil_value();
+  }
+
+  opt = FALSE;
+  i = 0;
   while ((c = *format++)) {
+    mrb_value *argv = ARGV;
+    mrb_bool altmode;
+
     switch (c) {
-    case '|': case '*': case '&': case '?':
+    case '|': case '*': case '&': case '?': case ':':
       break;
     default:
@@ -599,4 +662,12 @@
     }
 
+    if (*format == '!') {
+      format ++;
+      altmode = TRUE;
+    }
+    else {
+      altmode = FALSE;
+    }
+
     switch (c) {
     case 'o':
@@ -606,6 +677,5 @@
         p = va_arg(ap, mrb_value*);
         if (i < argc) {
-          *p = ARGV[arg_i++];
-          i++;
+          *p = argv[i++];
         }
       }
@@ -619,10 +689,9 @@
           mrb_value ss;
 
-          ss = ARGV[arg_i++];
+          ss = argv[i++];
           if (!class_ptr_p(ss)) {
-            mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
+            mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss);
           }
           *p = ss;
-          i++;
         }
       }
@@ -633,15 +702,9 @@
 
         p = va_arg(ap, mrb_value*);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
-            *p = ARGV[arg_i++];
-            i++;
-            break;
+        if (i < argc) {
+          *p = argv[i++];
+          if (!(altmode && mrb_nil_p(*p))) {
+            mrb_to_str(mrb, *p);
           }
-        }
-        if (i < argc) {
-          *p = to_str(mrb, ARGV[arg_i++]);
-          i++;
         }
       }
@@ -652,15 +715,9 @@
 
         p = va_arg(ap, mrb_value*);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
-            *p = ARGV[arg_i++];
-            i++;
-            break;
+        if (i < argc) {
+          *p = argv[i++];
+          if (!(altmode && mrb_nil_p(*p))) {
+            *p = to_ary(mrb, *p);
           }
-        }
-        if (i < argc) {
-          *p = to_ary(mrb, ARGV[arg_i++]);
-          i++;
         }
       }
@@ -671,15 +728,9 @@
 
         p = va_arg(ap, mrb_value*);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
-            *p = ARGV[arg_i++];
-            i++;
-            break;
+        if (i < argc) {
+          *p = argv[i++];
+          if (!(altmode && mrb_nil_p(*p))) {
+            *p = to_hash(mrb, *p);
           }
-        }
-        if (i < argc) {
-          *p = to_hash(mrb, ARGV[arg_i++]);
-          i++;
         }
       }
@@ -693,18 +744,15 @@
         ps = va_arg(ap, char**);
         pl = va_arg(ap, mrb_int*);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+        if (i < argc) {
+          ss = argv[i++];
+          if (altmode && mrb_nil_p(ss)) {
             *ps = NULL;
             *pl = 0;
-            i++; arg_i++;
-            break;
           }
-        }
-        if (i < argc) {
-          ss = to_str(mrb, ARGV[arg_i++]);
-          *ps = RSTRING_PTR(ss);
-          *pl = RSTRING_LEN(ss);
-          i++;
+          else {
+            mrb_to_str(mrb, ss);
+            *ps = RSTRING_PTR(ss);
+            *pl = RSTRING_LEN(ss);
+          }
         }
       }
@@ -716,16 +764,13 @@
 
         ps = va_arg(ap, const char**);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+        if (i < argc) {
+          ss = argv[i++];
+          if (altmode && mrb_nil_p(ss)) {
             *ps = NULL;
-            i++; arg_i++;
-            break;
           }
-        }
-        if (i < argc) {
-          ss = to_str(mrb, ARGV[arg_i++]);
-          *ps = mrb_string_value_cstr(mrb, &ss);
-          i++;
+          else {
+            mrb_to_str(mrb, ss);
+            *ps = RSTRING_CSTR(mrb, ss);
+          }
         }
       }
@@ -740,19 +785,16 @@
         pb = va_arg(ap, mrb_value**);
         pl = va_arg(ap, mrb_int*);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+        if (i < argc) {
+          aa = argv[i++];
+          if (altmode && mrb_nil_p(aa)) {
             *pb = 0;
             *pl = 0;
-            i++; arg_i++;
-            break;
           }
-        }
-        if (i < argc) {
-          aa = to_ary(mrb, ARGV[arg_i++]);
-          a = mrb_ary_ptr(aa);
-          *pb = a->ptr;
-          *pl = a->len;
-          i++;
+          else {
+            aa = to_ary(mrb, aa);
+            a = mrb_ary_ptr(aa);
+            *pb = ARY_PTR(a);
+            *pl = ARY_LEN(a);
+          }
         }
       }
@@ -765,15 +807,14 @@
         p = va_arg(ap, void**);
         if (i < argc) {
-          ss = ARGV[arg_i];
-          if (mrb_type(ss) != MRB_TT_ISTRUCT)
+          ss = argv[i++];
+          if (!mrb_istruct_p(ss))
           {
-            mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
+            mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss);
           }
           *p = mrb_istruct_ptr(ss);
-          arg_i++;
-          i++;
-        }
-      }
-      break;
+        }
+      }
+      break;
+#ifndef MRB_WITHOUT_FLOAT
     case 'f':
       {
@@ -782,10 +823,9 @@
         p = va_arg(ap, mrb_float*);
         if (i < argc) {
-          *p = mrb_to_flo(mrb, ARGV[arg_i]);
-          arg_i++;
-          i++;
-        }
-      }
-      break;
+          *p = mrb_to_flo(mrb, argv[i++]);
+        }
+      }
+      break;
+#endif
     case 'i':
       {
@@ -794,27 +834,5 @@
         p = va_arg(ap, mrb_int*);
         if (i < argc) {
-          switch (mrb_type(ARGV[arg_i])) {
-            case MRB_TT_FIXNUM:
-              *p = mrb_fixnum(ARGV[arg_i]);
-              break;
-            case MRB_TT_FLOAT:
-              {
-                mrb_float f = mrb_float(ARGV[arg_i]);
-
-                if (!FIXABLE_FLOAT(f)) {
-                  mrb_raise(mrb, E_RANGE_ERROR, "float too big for int");
-                }
-                *p = (mrb_int)f;
-              }
-              break;
-            case MRB_TT_STRING:
-              mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer");
-              break;
-            default:
-              *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i]));
-              break;
-          }
-          arg_i++;
-          i++;
+          *p = mrb_fixnum(mrb_to_int(mrb, argv[i++]));
         }
       }
@@ -825,7 +843,6 @@
 
         if (i < argc) {
-          mrb_value b = ARGV[arg_i++];
+          mrb_value b = argv[i++];
           *boolp = mrb_test(b);
-          i++;
         }
       }
@@ -839,7 +856,6 @@
           mrb_value ss;
 
-          ss = ARGV[arg_i++];
+          ss = argv[i++];
           *symp = to_sym(mrb, ss);
-          i++;
         }
       }
@@ -852,15 +868,12 @@
         datap = va_arg(ap, void**);
         type = va_arg(ap, struct mrb_data_type const*);
-        if (*format == '!') {
-          format++;
-          if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+        if (i < argc) {
+          mrb_value dd = argv[i++];
+          if (altmode && mrb_nil_p(dd)) {
             *datap = 0;
-            i++; arg_i++;
-            break;
           }
-        }
-        if (i < argc) {
-          *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type);
-          ++i;
+          else {
+            *datap = mrb_data_get_ptr(mrb, dd, type);
+          }
         }
       }
@@ -878,8 +891,12 @@
           bp = mrb->c->stack + mrb->c->ci->argc + 1;
         }
+        if (altmode && mrb_nil_p(*bp)) {
+          mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+        }
         *p = *bp;
       }
       break;
     case '|':
+      if (opt_skip && i == argc) goto finish;
       opt = TRUE;
       break;
@@ -897,4 +914,5 @@
         mrb_value **var;
         mrb_int *pl;
+        mrb_bool nocopy = (altmode || !argv_on_stack) ? TRUE : FALSE;
 
         var = va_arg(ap, mrb_value**);
@@ -903,8 +921,14 @@
           *pl = argc-i;
           if (*pl > 0) {
-            *var = ARGV + arg_i;
+            if (nocopy) {
+              *var = argv+i;
+            }
+            else {
+              mrb_value args = mrb_ary_new_from_values(mrb, *pl, argv+i);
+              RARRAY(args)->c = NULL;
+              *var = RARRAY_PTR(args);
+            }
           }
           i = argc;
-          arg_i += *pl;
         }
         else {
@@ -914,6 +938,62 @@
       }
       break;
+
+    case ':':
+      {
+        mrb_value ksrc = mrb_hash_p(kdict) ? mrb_hash_dup(mrb, kdict) : mrb_hash_new(mrb);
+        const mrb_kwargs *kwargs = va_arg(ap, const mrb_kwargs*);
+        mrb_value *rest;
+
+        if (kwargs == NULL) {
+          rest = NULL;
+        }
+        else {
+          uint32_t kwnum = kwargs->num;
+          uint32_t required = kwargs->required;
+          const char *const *kname = kwargs->table;
+          mrb_value *values = kwargs->values;
+          uint32_t j;
+          const uint32_t keyword_max = 40;
+
+          if (kwnum > keyword_max || required > kwnum) {
+            mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword number is too large");
+          }
+
+          for (j = required; j > 0; j --, kname ++, values ++) {
+            mrb_value k = mrb_symbol_value(mrb_intern_cstr(mrb, *kname));
+            if (!mrb_hash_key_p(mrb, ksrc, k)) {
+              mrb_raisef(mrb, E_ARGUMENT_ERROR, "missing keyword: %s", *kname);
+            }
+            *values = mrb_hash_delete_key(mrb, ksrc, k);
+            mrb_gc_protect(mrb, *values);
+          }
+
+          for (j = kwnum - required; j > 0; j --, kname ++, values ++) {
+            mrb_value k = mrb_symbol_value(mrb_intern_cstr(mrb, *kname));
+            if (mrb_hash_key_p(mrb, ksrc, k)) {
+              *values = mrb_hash_delete_key(mrb, ksrc, k);
+              mrb_gc_protect(mrb, *values);
+            }
+            else {
+              *values = mrb_undef_value();
+            }
+          }
+
+          rest = kwargs->rest;
+        }
+
+        if (rest) {
+          *rest = ksrc;
+        }
+        else if (!mrb_hash_empty_p(mrb, ksrc)) {
+          ksrc = mrb_hash_keys(mrb, ksrc);
+          ksrc = RARRAY_PTR(ksrc)[0];
+          mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown keyword: %v", ksrc);
+        }
+      }
+      break;
+
     default:
-      mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1));
+      mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c);
       break;
     }
@@ -925,4 +1005,6 @@
     mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
   }
+
+finish:
   va_end(ap);
   return i;
@@ -983,5 +1065,5 @@
     int superclass_seen = 0;
 
-    if (m->flags & MRB_FLAG_IS_PREPENDED)
+    if (m->flags & MRB_FL_CLASS_IS_PREPENDED)
       goto skip;
 
@@ -990,5 +1072,5 @@
 
     p = c->super;
-    while(p) {
+    while (p) {
       if (p->tt == MRB_TT_ICLASS) {
         if (p->mt == m->mt) {
@@ -1006,10 +1088,13 @@
 
     ic = include_class_new(mrb, m, ins_pos->super);
+    m->flags |= MRB_FL_CLASS_IS_INHERITED;
     ins_pos->super = ic;
-    mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ins_pos->super);
+    mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic);
+    mrb_mc_clear_by_class(mrb, ins_pos);
     ins_pos = ic;
   skip:
     m = m->super;
   }
+  mc_clear_all(mrb);
   return 0;
 }
@@ -1018,6 +1103,6 @@
 mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
 {
-  int changed = include_module_at(mrb, c, find_origin(c), m, 1);
-  if (changed < 0) {
+  mrb_check_frozen(mrb, c);
+  if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
   }
@@ -1030,7 +1115,8 @@
   int changed = 0;
 
-  if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
+  mrb_check_frozen(mrb, c);
+  if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) {
     origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
-    origin->flags |= MRB_FLAG_IS_ORIGIN;
+    origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED;
     origin->super = c->super;
     c->super = origin;
@@ -1038,5 +1124,5 @@
     c->mt = kh_init(mt, mrb);
     mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin);
-    c->flags |= MRB_FLAG_IS_PREPENDED;
+    c->flags |= MRB_FL_CLASS_IS_PREPENDED;
   }
   changed = include_module_at(mrb, c, c, m, 0);
@@ -1115,5 +1201,5 @@
       mrb_ary_push(mrb, result, mrb_obj_value(c->c));
     }
-    else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
+    else if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) {
       mrb_ary_push(mrb, result, mrb_obj_value(c));
     }
@@ -1133,25 +1219,4 @@
   mrb_include_module(mrb, mrb_class_ptr(mrb_singleton_class(mrb, obj)), mrb_class_ptr(mod));
   return mod;
-}
-
-static mrb_value
-mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
-{
-  mrb_value result;
-  struct RClass *c = mrb_class_ptr(self);
-  struct RClass *origin = c;
-
-  MRB_CLASS_ORIGIN(origin);
-  result = mrb_ary_new(mrb);
-  while (c) {
-    if (c != origin && c->tt == MRB_TT_ICLASS) {
-      if (c->c->tt == MRB_TT_MODULE) {
-        mrb_ary_push(mrb, result, mrb_obj_value(c->c));
-      }
-    }
-    c = c->super;
-  }
-
-  return result;
 }
 
@@ -1167,43 +1232,4 @@
   }
   return mod;
-}
-
-mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
-
-/* 15.2.2.4.33 */
-/*
- *  call-seq:
- *     mod.instance_methods(include_super=true)   -> array
- *
- *  Returns an array containing the names of the public and protected instance
- *  methods in the receiver. For a module, these are the public and protected methods;
- *  for a class, they are the instance (not singleton) methods. With no
- *  argument, or with an argument that is <code>false</code>, the
- *  instance methods in <i>mod</i> are returned, otherwise the methods
- *  in <i>mod</i> and <i>mod</i>'s superclasses are returned.
- *
- *     module A
- *       def method1()  end
- *     end
- *     class B
- *       def method2()  end
- *     end
- *     class C < B
- *       def method3()  end
- *     end
- *
- *     A.instance_methods                #=> [:method1]
- *     B.instance_methods(false)         #=> [:method2]
- *     C.instance_methods(false)         #=> [:method3]
- *     C.instance_methods(true).length   #=> 43
- */
-
-static mrb_value
-mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
-{
-  struct RClass *c = mrb_class_ptr(mod);
-  mrb_bool recur = TRUE;
-  mrb_get_args(mrb, "|b", &recur);
-  return mrb_class_instance_method_list(mrb, recur, c, 0);
 }
 
@@ -1233,5 +1259,7 @@
   case MRB_TT_SYMBOL:
   case MRB_TT_FIXNUM:
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
+#endif
     mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton");
     return mrb_nil_value();    /* not reached */
@@ -1264,10 +1292,66 @@
 }
 
-MRB_API struct RProc*
+#ifdef MRB_METHOD_CACHE
+static void
+mc_clear_all(mrb_state *mrb)
+{
+  struct mrb_cache_entry *mc = mrb->cache;
+  int i;
+
+  for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+    mc[i].c = 0;
+  }
+}
+
+void
+mrb_mc_clear_by_class(mrb_state *mrb, struct RClass *c)
+{
+  struct mrb_cache_entry *mc = mrb->cache;
+  int i;
+
+  if (c->flags & MRB_FL_CLASS_IS_INHERITED) {
+    mc_clear_all(mrb);
+    c->flags &= ~MRB_FL_CLASS_IS_INHERITED;
+    return;
+  }
+  for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+    if (mc[i].c == c) mc[i].c = 0;
+  }
+}
+
+static void
+mc_clear_by_id(mrb_state *mrb, struct RClass *c, mrb_sym mid)
+{
+  struct mrb_cache_entry *mc = mrb->cache;
+  int i;
+
+  if (c->flags & MRB_FL_CLASS_IS_INHERITED) {
+    mc_clear_all(mrb);
+    c->flags &= ~MRB_FL_CLASS_IS_INHERITED;
+    return;
+  }
+  for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) {
+    if (mc[i].c == c || mc[i].mid == mid)
+      mc[i].c = 0;
+  }
+}
+#endif
+
+MRB_API mrb_method_t
 mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
 {
   khiter_t k;
-  struct RProc *m;
+  mrb_method_t m;
   struct RClass *c = *cp;
+#ifdef MRB_METHOD_CACHE
+  struct RClass *oc = c;
+  int h = kh_int_hash_func(mrb, ((intptr_t)oc) ^ mid) & (MRB_METHOD_CACHE_SIZE-1);
+  struct mrb_cache_entry *mc = &mrb->cache[h];
+
+  if (mc->c == c && mc->mid == mid) {
+    *cp = mc->c0;
+    return mc->m;
+  }
+#endif
 
   while (c) {
@@ -1278,6 +1362,12 @@
       if (k != kh_end(h)) {
         m = kh_value(h, k);
-        if (!m) break;
+        if (MRB_METHOD_UNDEF_P(m)) break;
         *cp = c;
+#ifdef MRB_METHOD_CACHE
+        mc->c = oc;
+        mc->c0 = c;
+        mc->mid = mid;
+        mc->m = m;
+#endif
         return m;
       }
@@ -1285,33 +1375,66 @@
     c = c->super;
   }
-  return NULL;                  /* no method */
-}
-
-MRB_API struct RProc*
+  MRB_METHOD_FROM_PROC(m, NULL);
+  return m;                  /* no method */
+}
+
+MRB_API mrb_method_t
 mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
 {
-  struct RProc *m;
+  mrb_method_t m;
 
   m = mrb_method_search_vm(mrb, &c, mid);
-  if (!m) {
-    mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0);
-    if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) {
-      inspect = mrb_any_to_s(mrb, mrb_obj_value(c));
-    }
-    mrb_name_error(mrb, mid, "undefined method '%S' for class %S",
-               mrb_sym2str(mrb, mid), inspect);
+  if (MRB_METHOD_UNDEF_P(m)) {
+    mrb_name_error(mrb, mid, "undefined method '%n' for class %C", mid, c);
   }
   return m;
 }
 
-static mrb_value
-attr_reader(mrb_state *mrb, mrb_value obj)
-{
-  mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
-  return mrb_iv_get(mrb, obj, to_sym(mrb, name));
-}
-
-static mrb_value
-mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+#define ONSTACK_ALLOC_MAX 32
+
+static mrb_sym
+prepare_name_common(mrb_state *mrb, mrb_sym sym, const char *prefix, const char *suffix)
+{
+  char onstack[ONSTACK_ALLOC_MAX];
+  mrb_int sym_len;
+  const char *sym_str = mrb_sym_name_len(mrb, sym, &sym_len);
+  size_t prefix_len = prefix ? strlen(prefix) : 0;
+  size_t suffix_len = suffix ? strlen(suffix) : 0;
+  size_t name_len = sym_len + prefix_len + suffix_len;
+  char *buf = name_len > sizeof(onstack) ? (char *)mrb_alloca(mrb, name_len) : onstack;
+  char *p = buf;
+
+  if (prefix_len > 0) {
+    memcpy(p, prefix, prefix_len);
+    p += prefix_len;
+  }
+
+  memcpy(p, sym_str, sym_len);
+  p += sym_len;
+
+  if (suffix_len > 0) {
+    memcpy(p, suffix, suffix_len);
+    p += suffix_len;
+  }
+
+  return mrb_intern(mrb, buf, name_len);
+}
+
+static mrb_value
+prepare_ivar_name(mrb_state *mrb, mrb_sym sym)
+{
+  sym = prepare_name_common(mrb, sym, "@", NULL);
+  mrb_iv_name_sym_check(mrb, sym);
+  return mrb_symbol_value(sym);
+}
+
+static mrb_sym
+prepare_writer_name(mrb_state *mrb, mrb_sym sym)
+{
+  return prepare_name_common(mrb, sym, NULL, "=");
+}
+
+static mrb_value
+mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state *, mrb_value), mrb_sym (*access_name)(mrb_state *, mrb_sym))
 {
   struct RClass *c = mrb_class_ptr(mod);
@@ -1323,20 +1446,34 @@
   ai = mrb_gc_arena_save(mrb);
   for (i=0; i<argc; i++) {
-    mrb_value name, str;
-    mrb_sym method, sym;
+    mrb_value name;
+    mrb_sym method;
+    struct RProc *p;
+    mrb_method_t m;
 
     method = to_sym(mrb, argv[i]);
-    name = mrb_sym2str(mrb, method);
-    str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1);
-    mrb_str_cat_lit(mrb, str, "@");
-    mrb_str_cat_str(mrb, str, name);
-    sym = mrb_intern_str(mrb, str);
-    mrb_iv_check(mrb, sym);
-    name = mrb_symbol_value(sym);
-    mrb_define_method_raw(mrb, c, method,
-                          mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name));
+    name = prepare_ivar_name(mrb, method);
+    if (access_name) {
+      method = access_name(mrb, method);
+    }
+
+    p = mrb_proc_new_cfunc_with_env(mrb, accessor, 1, &name);
+    MRB_METHOD_FROM_PROC(m, p);
+    mrb_define_method_raw(mrb, c, method, m);
     mrb_gc_arena_restore(mrb, ai);
   }
   return mrb_nil_value();
+}
+
+static mrb_value
+attr_reader(mrb_state *mrb, mrb_value obj)
+{
+  mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+  return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+}
+
+static mrb_value
+mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+{
+  return mod_attr_define(mrb, mod, attr_reader, NULL);
 }
 
@@ -1355,37 +1492,5 @@
 mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod)
 {
-  struct RClass *c = mrb_class_ptr(mod);
-  mrb_value *argv;
-  mrb_int argc, i;
-  int ai;
-
-  mrb_get_args(mrb, "*", &argv, &argc);
-  ai = mrb_gc_arena_save(mrb);
-  for (i=0; i<argc; i++) {
-    mrb_value name, str, attr;
-    mrb_sym method, sym;
-
-    method = to_sym(mrb, argv[i]);
-
-    /* prepare iv name (@name) */
-    name = mrb_sym2str(mrb, method);
-    str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1);
-    mrb_str_cat_lit(mrb, str, "@");
-    mrb_str_cat_str(mrb, str, name);
-    sym = mrb_intern_str(mrb, str);
-    mrb_iv_check(mrb, sym);
-    attr = mrb_symbol_value(sym);
-
-    /* prepare method name (name=) */
-    str = mrb_str_buf_new(mrb, RSTRING_LEN(str));
-    mrb_str_cat_str(mrb, str, name);
-    mrb_str_cat_lit(mrb, str, "=");
-    method = mrb_intern_str(mrb, str);
-
-    mrb_define_method_raw(mrb, c, method,
-                          mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr));
-    mrb_gc_arena_restore(mrb, ai);
-  }
-  return mrb_nil_value();
+  return mod_attr_define(mrb, mod, attr_writer, prepare_writer_name);
 }
 
@@ -1402,5 +1507,5 @@
   if (ttype == 0) ttype = MRB_TT_OBJECT;
   if (ttype <= MRB_TT_CPTR) {
-    mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv);
+    mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %v", cv);
   }
   o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
@@ -1420,5 +1525,5 @@
  */
 
-MRB_API mrb_value
+mrb_value
 mrb_instance_new(mrb_state *mrb, mrb_value cv)
 {
@@ -1426,9 +1531,12 @@
   mrb_value *argv;
   mrb_int argc;
-
-  mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+  mrb_sym init;
+
+  mrb_get_args(mrb, "*!&", &argv, &argc, &blk);
   obj = mrb_instance_alloc(mrb, cv);
-  mrb_funcall_with_block(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv, blk);
-
+  init = mrb_intern_lit(mrb, "initialize");
+  if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) {
+    mrb_funcall_with_block(mrb, obj, init, argc, argv, blk);
+  }
   return obj;
 }
@@ -1474,5 +1582,8 @@
   new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
   mid = mrb_intern_lit(mrb, "initialize");
-  if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) {
+  if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) {
+    mrb_class_initialize(mrb, new_class);
+  }
+  else {
     mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
   }
@@ -1559,23 +1670,11 @@
 mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
 {
-  khiter_t k;
-
-  while (c) {
-    khash_t(mt) *h = c->mt;
-
-    if (h) {
-      k = kh_get(mt, mrb, h, mid);
-      if (k != kh_end(h)) {
-        if (kh_value(h, k)) {
-          return TRUE;  /* method exists */
-        }
-        else {
-          return FALSE; /* undefined method */
-        }
-      }
-    }
-    c = c->super;
-  }
-  return FALSE;         /* no method */
+  mrb_method_t m;
+
+  m = mrb_method_search_vm(mrb, &c, mid);
+  if (MRB_METHOD_UNDEF_P(m)) {
+    return FALSE;
+  }
+  return TRUE;
 }
 
@@ -1590,49 +1689,25 @@
 {
   mrb_value path;
-  const char *name;
-  mrb_sym classpath = mrb_intern_lit(mrb, "__classpath__");
-
-  path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath);
+  mrb_sym nsym = mrb_intern_lit(mrb, "__classname__");
+
+  path = mrb_obj_iv_get(mrb, (struct RObject*)c, nsym);
   if (mrb_nil_p(path)) {
-    struct RClass *outer = mrb_class_outer_module(mrb, c);
-    mrb_sym sym = mrb_class_sym(mrb, c, outer);
-    mrb_int len;
-
-    if (sym == 0) {
-      return mrb_nil_value();
-    }
-    else if (outer && outer != c && outer != mrb->object_class) {
-      mrb_value base = mrb_class_path(mrb, outer);
-      path = mrb_str_buf_new(mrb, 0);
-      if (mrb_nil_p(base)) {
-        mrb_str_cat_lit(mrb, path, "#<Class:");
-        mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, outer));
-        mrb_str_cat_lit(mrb, path, ">");
-      }
-      else {
-        mrb_str_concat(mrb, path, base);
-      }
-      mrb_str_cat_lit(mrb, path, "::");
-      name = mrb_sym2name_len(mrb, sym, &len);
-      mrb_str_cat(mrb, path, name, len);
-    }
-    else {
-      name = mrb_sym2name_len(mrb, sym, &len);
-      path = mrb_str_new(mrb, name, len);
-    }
-    if (!MRB_FROZEN_P(c)) {
-      mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
-    }
+    /* no name (yet) */
+    return mrb_class_find_path(mrb, c);
+  }
+  else if (mrb_symbol_p(path)) {
+    /* toplevel class/module */
+    return mrb_sym_str(mrb, mrb_symbol(path));
   }
   return mrb_str_dup(mrb, path);
 }
 
-MRB_API struct RClass *
+MRB_API struct RClass*
 mrb_class_real(struct RClass* cl)
 {
-  if (cl == 0)
-    return NULL;
+  if (cl == 0) return NULL;
   while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) {
     cl = cl->super;
+    if (cl == 0) return NULL;
   }
   return cl;
@@ -1642,11 +1717,6 @@
 mrb_class_name(mrb_state *mrb, struct RClass* c)
 {
-  mrb_value path = mrb_class_path(mrb, c);
-  if (mrb_nil_p(path)) {
-    path = mrb_str_new_lit(mrb, "#<Class:");
-    mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
-    mrb_str_cat_lit(mrb, path, ">");
-  }
-  return RSTRING_PTR(path);
+  mrb_value name = class_name_str(mrb, c);
+  return RSTRING_PTR(name);
 }
 
@@ -1667,5 +1737,5 @@
 {
   if (super->tt != MRB_TT_CLASS) {
-    mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super));
+    mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%C given)", super);
   }
   if (super->tt == MRB_TT_SCLASS) {
@@ -1734,6 +1804,25 @@
 mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
 {
-  struct RProc *m = mrb_method_search(mrb, c, b);
-
+  mrb_method_t m = mrb_method_search(mrb, c, b);
+
+  if (!MRB_METHOD_CFUNC_P(m)) {
+    struct RProc *p = MRB_METHOD_PROC(m);
+
+    if (MRB_PROC_ENV_P(p)) {
+      MRB_PROC_ENV(p)->mid = b;
+    }
+    else {
+      struct RClass *tc = MRB_PROC_TARGET_CLASS(p);
+      struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL);
+
+      e->mid = b;
+      if (tc) {
+        e->c = tc;
+        mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc);
+      }
+      p->e.env = e;
+      p->flags |= MRB_PROC_ENVSET;
+    }
+  }
   mrb_define_method_raw(mrb, c, a, m);
 }
@@ -1741,4 +1830,5 @@
 /*!
  * Defines an alias of a method.
+ * \param mrb    the mruby state
  * \param klass  the class which the original method belongs to
  * \param name1  a new name for the method
@@ -1760,13 +1850,11 @@
  */
 
-static mrb_value
+mrb_value
 mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
 {
-  mrb_value str;
-
-  if (mrb_type(klass) == MRB_TT_SCLASS) {
+
+  if (mrb_sclass_p(klass)) {
     mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__"));
-
-    str = mrb_str_new_lit(mrb, "#<Class:");
+    mrb_value str = mrb_str_new_lit(mrb, "#<Class:");
 
     if (class_ptr_p(v)) {
@@ -1779,32 +1867,5 @@
   }
   else {
-    struct RClass *c;
-    mrb_value path;
-
-    str = mrb_str_buf_new(mrb, 32);
-    c = mrb_class_ptr(klass);
-    path = mrb_class_path(mrb, c);
-
-    if (mrb_nil_p(path)) {
-      switch (mrb_type(klass)) {
-        case MRB_TT_CLASS:
-          mrb_str_cat_lit(mrb, str, "#<Class:");
-          break;
-
-        case MRB_TT_MODULE:
-          mrb_str_cat_lit(mrb, str, "#<Module:");
-          break;
-
-        default:
-          /* Shouldn't be happened? */
-          mrb_str_cat_lit(mrb, str, "#<??????:");
-          break;
-      }
-      mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c));
-      return mrb_str_cat_lit(mrb, str, ">");
-    }
-    else {
-      return path;
-    }
+    return class_name_str(mrb, mrb_class_ptr(klass));
   }
 }
@@ -1818,5 +1879,5 @@
   mrb_get_args(mrb, "nn", &new_name, &old_name);
   mrb_alias_method(mrb, c, new_name, old_name);
-  return mrb_nil_value();
+  return mod;
 }
 
@@ -1824,10 +1885,17 @@
 undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
 {
+  mrb_method_t m;
+
+  MRB_METHOD_FROM_PROC(m, NULL);
+  mrb_define_method_raw(mrb, c, a, m);
+}
+
+void
+mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a)
+{
   if (!mrb_obj_respond_to(mrb, c, a)) {
-    mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c));
-  }
-  else {
-    mrb_define_method_raw(mrb, c, a, NULL);
-  }
+    mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c);
+  }
+  undef_method(mrb, c, a);
 }
 
@@ -1853,5 +1921,5 @@
   mrb_get_args(mrb, "*", &argv, &argc);
   while (argc--) {
-    undef_method(mrb, c, to_sym(mrb, *argv));
+    mrb_undef_method_id(mrb, c, to_sym(mrb, *argv));
     argv++;
   }
@@ -1859,177 +1927,117 @@
 }
 
-static mrb_value
-mod_define_method(mrb_state *mrb, mrb_value self)
-{
-  struct RClass *c = mrb_class_ptr(self);
-  struct RProc *p;
-  mrb_sym mid;
-  mrb_value proc = mrb_undef_value();
-  mrb_value blk;
-
-  mrb_get_args(mrb, "n|o&", &mid, &proc, &blk);
-  switch (mrb_type(proc)) {
-    case MRB_TT_PROC:
-      blk = proc;
-      break;
-    case MRB_TT_UNDEF:
-      /* ignored */
-      break;
-    default:
-      mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
-      break;
-  }
-  if (mrb_nil_p(blk)) {
-    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
-  }
-  p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
-  mrb_proc_copy(p, mrb_proc_ptr(blk));
-  p->flags |= MRB_PROC_STRICT;
-  mrb_define_method_raw(mrb, c, mid, p);
-  return mrb_symbol_value(mid);
-}
-
 static void
-check_cv_name_str(mrb_state *mrb, mrb_value str)
-{
-  const char *s = RSTRING_PTR(str);
-  mrb_int len = RSTRING_LEN(str);
-
-  if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
-    mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str);
-  }
-}
-
-static void
-check_cv_name_sym(mrb_state *mrb, mrb_sym id)
-{
-  check_cv_name_str(mrb, mrb_sym2str(mrb, id));
-}
-
-/* 15.2.2.4.16 */
-/*
- *  call-seq:
- *     obj.class_variable_defined?(symbol)    -> true or false
- *
- *  Returns <code>true</code> if the given class variable is defined
- *  in <i>obj</i>.
- *
- *     class Fred
- *       @@foo = 99
- *     end
- *     Fred.class_variable_defined?(:@@foo)    #=> true
- *     Fred.class_variable_defined?(:@@bar)    #=> false
- */
-
-static mrb_value
-mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod)
+check_const_name_sym(mrb_state *mrb, mrb_sym id)
+{
+  mrb_int len;
+  const char *name = mrb_sym_name_len(mrb, id, &len);
+  if (!mrb_const_name_p(mrb, name, len)) {
+    mrb_name_error(mrb, id, "wrong constant name %n", id);
+  }
+}
+
+static mrb_value
+mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
 {
   mrb_sym id;
+  mrb_bool inherit = TRUE;
+
+  mrb_get_args(mrb, "n|b", &id, &inherit);
+  check_const_name_sym(mrb, id);
+  if (inherit) {
+    return mrb_bool_value(mrb_const_defined(mrb, mod, id));
+  }
+  return mrb_bool_value(mrb_const_defined_at(mrb, mod, id));
+}
+
+static mrb_value
+mrb_const_get_sym(mrb_state *mrb, mrb_value mod, mrb_sym id)
+{
+  check_const_name_sym(mrb, id);
+  return mrb_const_get(mrb, mod, id);
+}
+
+static mrb_value
+mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
+{
+  mrb_value path;
+  mrb_sym id;
+  char *ptr;
+  mrb_int off, end, len;
+
+  mrb_get_args(mrb, "o", &path);
+
+  if (mrb_symbol_p(path)) {
+    /* const get with symbol */
+    id = mrb_symbol(path);
+    return mrb_const_get_sym(mrb, mod, id);
+  }
+
+  /* const get with class path string */
+  path = mrb_ensure_string_type(mrb, path);
+  ptr = RSTRING_PTR(path);
+  len = RSTRING_LEN(path);
+  off = 0;
+
+  while (off < len) {
+    end = mrb_str_index_lit(mrb, path, "::", off);
+    end = (end == -1) ? len : end;
+    id = mrb_intern(mrb, ptr+off, end-off);
+    mod = mrb_const_get_sym(mrb, mod, id);
+    if (end == len)
+      off = end;
+    else {
+      off = end + 2;
+      if (off == len) {         /* trailing "::" */
+        mrb_name_error(mrb, id, "wrong constant name '%v'", path);
+      }
+    }
+  }
+
+  return mod;
+}
+
+static mrb_value
+mrb_mod_const_set(mrb_state *mrb, mrb_value mod)
+{
+  mrb_sym id;
+  mrb_value value;
+
+  mrb_get_args(mrb, "no", &id, &value);
+  check_const_name_sym(mrb, id);
+  mrb_const_set(mrb, mod, id, value);
+  return value;
+}
+
+static mrb_value
+mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
+{
+  mrb_sym id;
+  mrb_value val;
 
   mrb_get_args(mrb, "n", &id);
-  check_cv_name_sym(mrb, id);
-  return mrb_bool_value(mrb_cv_defined(mrb, mod, id));
-}
-
-/* 15.2.2.4.17 */
-/*
- *  call-seq:
- *     mod.class_variable_get(symbol)    -> obj
- *
- *  Returns the value of the given class variable (or throws a
- *  <code>NameError</code> exception). The <code>@@</code> part of the
- *  variable name should be included for regular class variables
- *
- *     class Fred
- *       @@foo = 99
- *     end
- *     Fred.class_variable_get(:@@foo)     #=> 99
- */
-
-static mrb_value
-mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod)
-{
-  mrb_sym id;
-
-  mrb_get_args(mrb, "n", &id);
-  check_cv_name_sym(mrb, id);
-  return mrb_cv_get(mrb, mod, id);
-}
-
-/* 15.2.2.4.18 */
-/*
- *  call-seq:
- *     obj.class_variable_set(symbol, obj)    -> obj
- *
- *  Sets the class variable names by <i>symbol</i> to
- *  <i>object</i>.
- *
- *     class Fred
- *       @@foo = 99
- *       def foo
- *         @@foo
- *       end
- *     end
- *     Fred.class_variable_set(:@@foo, 101)     #=> 101
- *     Fred.new.foo                             #=> 101
- */
-
-static mrb_value
-mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod)
-{
-  mrb_value value;
-  mrb_sym id;
-
-  mrb_get_args(mrb, "no", &id, &value);
-  check_cv_name_sym(mrb, id);
-  mrb_cv_set(mrb, mod, id, value);
-  return value;
-}
-
-/* 15.2.2.4.39 */
-/*
- *  call-seq:
- *     remove_class_variable(sym)    -> obj
- *
- *  Removes the definition of the <i>sym</i>, returning that
- *  constant's value.
- *
- *     class Dummy
- *       @@var = 99
- *       puts @@var
- *       p class_variables
- *       remove_class_variable(:@@var)
- *       p class_variables
- *     end
- *
- *  <em>produces:</em>
- *
- *     99
- *     [:@@var]
- *     []
- */
-
-static mrb_value
-mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod)
-{
-  mrb_value val;
-  mrb_sym id;
-
-  mrb_get_args(mrb, "n", &id);
-  check_cv_name_sym(mrb, id);
-
+  check_const_name_sym(mrb, id);
   val = mrb_iv_remove(mrb, mod, id);
-  if (!mrb_undef_p(val)) return val;
-
-  if (mrb_cv_defined(mrb, mod, id)) {
-    mrb_name_error(mrb, id, "cannot remove %S for %S",
-                   mrb_sym2str(mrb, id), mod);
-  }
-
-  mrb_name_error(mrb, id, "class variable %S not defined for %S",
-                 mrb_sym2str(mrb, id), mod);
-
- /* not reached */
- return mrb_nil_value();
+  if (mrb_undef_p(val)) {
+    mrb_name_error(mrb, id, "constant %n not defined", id);
+  }
+  return val;
+}
+
+static mrb_value
+mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
+{
+  mrb_sym sym;
+
+  mrb_get_args(mrb, "n", &sym);
+
+  if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) {
+    mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym);
+  }
+  else {
+    mrb_name_error(mrb, sym, "uninitialized constant %n", sym);
+  }
+  /* not reached */
+  return mrb_nil_value();
 }
 
@@ -2070,145 +2078,41 @@
 }
 
-static void
-remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
-{
-  struct RClass *c = mrb_class_ptr(mod);
-  khash_t(mt) *h = find_origin(c)->mt;
-  khiter_t k;
-
-  if (h) {
-    k = kh_get(mt, mrb, h, mid);
-    if (k != kh_end(h)) {
-      kh_del(mt, mrb, h, k);
-      mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid));
-      return;
-    }
-  }
-
-  mrb_name_error(mrb, mid, "method '%S' not defined in %S",
-    mrb_sym2str(mrb, mid), mod);
-}
-
-/* 15.2.2.4.41 */
-/*
- *  call-seq:
- *     remove_method(symbol)   -> self
- *
- *  Removes the method identified by _symbol_ from the current
- *  class. For an example, see <code>Module.undef_method</code>.
- */
-
-static mrb_value
-mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
-{
-  mrb_int argc;
-  mrb_value *argv;
-
-  mrb_get_args(mrb, "*", &argv, &argc);
-  while (argc--) {
-    remove_method(mrb, mod, to_sym(mrb, *argv));
-    argv++;
-  }
-  return mod;
-}
-
-
-
-static void
-check_const_name_str(mrb_state *mrb, mrb_value str)
-{
-  if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) {
-    mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str);
-  }
-}
-
-static void
-check_const_name_sym(mrb_state *mrb, mrb_sym id)
-{
-  check_const_name_str(mrb, mrb_sym2str(mrb, id));
-}
-
-static mrb_value
-const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit)
-{
-  if (inherit) {
-    return mrb_bool_value(mrb_const_defined(mrb, mod, id));
-  }
-  return mrb_bool_value(mrb_const_defined_at(mrb, mod, id));
-}
-
-static mrb_value
-mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
-{
-  mrb_sym id;
-  mrb_bool inherit = TRUE;
-
-  mrb_get_args(mrb, "n|b", &id, &inherit);
-  check_const_name_sym(mrb, id);
-  return const_defined(mrb, mod, id, inherit);
-}
-
-static mrb_value
-mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
-{
-  mrb_sym id;
-
-  mrb_get_args(mrb, "n", &id);
-  check_const_name_sym(mrb, id);
-  return mrb_const_get(mrb, mod, id);
-}
-
-static mrb_value
-mrb_mod_const_set(mrb_state *mrb, mrb_value mod)
-{
-  mrb_sym id;
-  mrb_value value;
-
-  mrb_get_args(mrb, "no", &id, &value);
-  check_const_name_sym(mrb, id);
-  mrb_const_set(mrb, mod, id, value);
-  return value;
-}
-
-static mrb_value
-mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
-{
-  mrb_sym id;
-  mrb_value val;
-
-  mrb_get_args(mrb, "n", &id);
-  check_const_name_sym(mrb, id);
-  val = mrb_iv_remove(mrb, mod, id);
-  if (mrb_undef_p(val)) {
-    mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id));
-  }
-  return val;
-}
-
-static mrb_value
-mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
-{
-  mrb_sym sym;
-
-  mrb_get_args(mrb, "n", &sym);
-
-  if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) {
-    mrb_name_error(mrb, sym, "uninitialized constant %S::%S",
-                   mod,
-                   mrb_sym2str(mrb, sym));
-  }
-  else {
-    mrb_name_error(mrb, sym, "uninitialized constant %S",
-                   mrb_sym2str(mrb, sym));
-  }
-  /* not reached */
-  return mrb_nil_value();
-}
-
-static mrb_value
-mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
-{
-  mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented");
-  return mrb_nil_value();       /* not reached */
+static mrb_value
+mod_define_method(mrb_state *mrb, mrb_value self)
+{
+  struct RClass *c = mrb_class_ptr(self);
+  struct RProc *p;
+  mrb_method_t m;
+  mrb_sym mid;
+  mrb_value proc = mrb_undef_value();
+  mrb_value blk;
+
+  mrb_get_args(mrb, "n|o&", &mid, &proc, &blk);
+  switch (mrb_type(proc)) {
+    case MRB_TT_PROC:
+      blk = proc;
+      break;
+    case MRB_TT_UNDEF:
+      /* ignored */
+      break;
+    default:
+      mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %T (expected Proc)", proc);
+      break;
+  }
+  if (mrb_nil_p(blk)) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+  }
+  p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+  mrb_proc_copy(p, mrb_proc_ptr(blk));
+  p->flags |= MRB_PROC_STRICT;
+  MRB_METHOD_FROM_PROC(m, p);
+  mrb_define_method_raw(mrb, c, mid, m);
+  return mrb_symbol_value(mid);
+}
+
+static mrb_value
+top_define_method(mrb_state *mrb, mrb_value self)
+{
+  return mod_define_method(mrb, mrb_obj_value(mrb->object_class));
 }
 
@@ -2225,5 +2129,13 @@
 }
 
-MRB_API mrb_value
+static mrb_value
+mrb_mod_dup(mrb_state *mrb, mrb_value self)
+{
+  mrb_value mod = mrb_obj_clone(mrb, self);
+  MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod));
+  return mod;
+}
+
+static mrb_value
 mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
 {
@@ -2231,5 +2143,5 @@
   mrb_int argc, i;
   mrb_sym mid;
-  struct RProc *method_rproc;
+  mrb_method_t m;
   struct RClass *rclass;
   int ai;
@@ -2251,9 +2163,9 @@
     mid = mrb_symbol(argv[i]);
     rclass = mrb_class_ptr(mod);
-    method_rproc = mrb_method_search(mrb, rclass, mid);
+    m = mrb_method_search(mrb, rclass, mid);
 
     prepare_singleton_class(mrb, (struct RBasic*)rclass);
     ai = mrb_gc_arena_save(mrb);
-    mrb_define_method_raw(mrb, rclass->c, mid, method_rproc);
+    mrb_define_method_raw(mrb, rclass->c, mid, m);
     mrb_gc_arena_restore(mrb, ai);
   }
@@ -2266,4 +2178,44 @@
 /* implementation of instance_eval */
 mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
+
+static mrb_value
+inspect_main(mrb_state *mrb, mrb_value mod)
+{
+  return mrb_str_new_lit(mrb, "main");
+}
+
+static const mrb_code new_iseq[] = {
+  OP_ENTER, 0x0, 0x10, 0x1,  /* OP_ENTER     0:0:1:0:0:0:1 */
+  OP_LOADSELF, 0x3,          /* OP_LOADSELF  R3 */
+  OP_SEND, 0x3, 0x0, 0x0,    /* OP_SEND      R3  :allocate  0 */
+  OP_MOVE, 0x0, 0x3,         /* OP_MOVE      R0  R3 */
+  OP_MOVE, 0x4, 0x1,         /* OP_MOVE      R4  R1 */
+  OP_MOVE, 0x5, 0x2,         /* OP_MOVE      R5  R2 */
+  OP_SENDVB, 0x3, 0x1,       /* OP_SENDVB    R4  :initialize */
+  OP_RETURN, 0x0             /* OP_RETURN    R0 */
+};
+
+static void
+init_class_new(mrb_state *mrb, struct RClass *cls)
+{
+  struct RProc *p;
+  mrb_method_t m;
+  mrb_irep *new_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep));
+  static const mrb_irep mrb_irep_zero = { 0 };
+
+  *new_irep = mrb_irep_zero;
+  new_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*2);
+  new_irep->syms[0] = mrb_intern_lit(mrb, "allocate");
+  new_irep->syms[1] = mrb_intern_lit(mrb, "initialize");
+  new_irep->slen = 2;
+  new_irep->flags = MRB_ISEQ_NO_FREE;
+  new_irep->iseq = new_iseq;
+  new_irep->ilen = sizeof(new_iseq);
+  new_irep->nregs = 6;
+  new_irep->nlocals = 3;
+  p = mrb_proc_new(mrb, new_irep);
+  MRB_METHOD_FROM_PROC(m, p);
+  mrb_define_method_raw(mrb, cls, mrb_intern_lit(mrb, "new"), m);
+}
 
 void
@@ -2289,5 +2241,4 @@
   /* name basic classes */
   mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob));
-  mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob));
   mrb_define_const(mrb, obj, "Object",      mrb_obj_value(obj));
   mrb_define_const(mrb, obj, "Module",      mrb_obj_value(mod));
@@ -2295,8 +2246,8 @@
 
   /* name each classes */
-  name_class(mrb, bob, mrb_intern_lit(mrb, "BasicObject"));
-  name_class(mrb, obj, mrb_intern_lit(mrb, "Object"));           /* 15.2.1 */
-  name_class(mrb, mod, mrb_intern_lit(mrb, "Module"));           /* 15.2.2 */
-  name_class(mrb, cls, mrb_intern_lit(mrb, "Class"));            /* 15.2.3 */
+  mrb_class_name_class(mrb, NULL, bob, mrb_intern_lit(mrb, "BasicObject"));
+  mrb_class_name_class(mrb, NULL, obj, mrb_intern_lit(mrb, "Object")); /* 15.2.1 */
+  mrb_class_name_class(mrb, NULL, mod, mrb_intern_lit(mrb, "Module")); /* 15.2.2 */
+  mrb_class_name_class(mrb, NULL, cls, mrb_intern_lit(mrb, "Class"));  /* 15.2.3 */
 
   mrb->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class);  /* 15.2.17 */
@@ -2308,18 +2259,18 @@
   mrb_define_method(mrb, bob, "==",                      mrb_obj_equal_m,          MRB_ARGS_REQ(1)); /* 15.3.1.3.1  */
   mrb_define_method(mrb, bob, "!=",                      mrb_obj_not_equal_m,      MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, bob, "__id__",                  mrb_obj_id_m,             MRB_ARGS_NONE()); /* 15.3.1.3.3  */
-  mrb_define_method(mrb, bob, "__send__",                mrb_f_send,               MRB_ARGS_ANY());  /* 15.3.1.3.4  */
-  mrb_define_method(mrb, bob, "instance_eval",           mrb_obj_instance_eval,    MRB_ARGS_ANY());  /* 15.3.1.3.18 */
-
-  mrb_define_class_method(mrb, cls, "new",               mrb_class_new_class,      MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, bob, "__id__",                  mrb_obj_id_m,             MRB_ARGS_NONE()); /* 15.3.1.3.4  */
+  mrb_define_method(mrb, bob, "__send__",                mrb_f_send,               MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK());  /* 15.3.1.3.5  */
+  mrb_define_method(mrb, bob, "equal?",                  mrb_obj_equal_m,          MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
+  mrb_define_method(mrb, bob, "instance_eval",           mrb_obj_instance_eval,    MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK());  /* 15.3.1.3.18 */
+
+  mrb_define_class_method(mrb, cls, "new",               mrb_class_new_class,      MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, cls, "allocate",                mrb_instance_alloc,       MRB_ARGS_NONE());
   mrb_define_method(mrb, cls, "superclass",              mrb_class_superclass,     MRB_ARGS_NONE()); /* 15.2.3.3.4 */
-  mrb_define_method(mrb, cls, "new",                     mrb_instance_new,         MRB_ARGS_ANY());  /* 15.2.3.3.3 */
   mrb_define_method(mrb, cls, "initialize",              mrb_class_initialize,     MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */
   mrb_define_method(mrb, cls, "inherited",               mrb_bob_init,             MRB_ARGS_REQ(1));
 
+  init_class_new(mrb, cls);
+
   MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE);
-  mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined,     MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */
-  mrb_define_method(mrb, mod, "class_variable_get",      mrb_mod_cvar_get,         MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */
-  mrb_define_method(mrb, mod, "class_variable_set",      mrb_mod_cvar_set,         MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
   mrb_define_method(mrb, mod, "extend_object",           mrb_mod_extend_object,    MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */
   mrb_define_method(mrb, mod, "extended",                mrb_bob_init,             MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */
@@ -2330,8 +2281,5 @@
   mrb_define_method(mrb, mod, "class_eval",              mrb_mod_module_eval,      MRB_ARGS_ANY());  /* 15.2.2.4.15 */
   mrb_define_method(mrb, mod, "included",                mrb_bob_init,             MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */
-  mrb_define_method(mrb, mod, "included_modules",        mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */
   mrb_define_method(mrb, mod, "initialize",              mrb_mod_initialize,       MRB_ARGS_NONE()); /* 15.2.2.4.31 */
-  mrb_define_method(mrb, mod, "instance_methods",        mrb_mod_instance_methods, MRB_ARGS_ANY());  /* 15.2.2.4.33 */
-  mrb_define_method(mrb, mod, "method_defined?",         mrb_mod_method_defined,   MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */
   mrb_define_method(mrb, mod, "module_eval",             mrb_mod_module_eval,      MRB_ARGS_ANY());  /* 15.2.2.4.35 */
   mrb_define_method(mrb, mod, "module_function",         mrb_mod_module_function,  MRB_ARGS_ANY());
@@ -2339,7 +2287,4 @@
   mrb_define_method(mrb, mod, "protected",               mrb_mod_dummy_visibility, MRB_ARGS_ANY());  /* 15.2.2.4.37 */
   mrb_define_method(mrb, mod, "public",                  mrb_mod_dummy_visibility, MRB_ARGS_ANY());  /* 15.2.2.4.38 */
-  mrb_define_method(mrb, mod, "remove_class_variable",   mrb_mod_remove_cvar,      MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
-  mrb_define_method(mrb, mod, "remove_method",           mrb_mod_remove_method,    MRB_ARGS_ANY());  /* 15.2.2.4.41 */
-  mrb_define_method(mrb, mod, "method_removed",          mrb_bob_init,             MRB_ARGS_REQ(1));
   mrb_define_method(mrb, mod, "attr_reader",             mrb_mod_attr_reader,      MRB_ARGS_ANY());  /* 15.2.2.4.13 */
   mrb_define_method(mrb, mod, "attr_writer",             mrb_mod_attr_writer,      MRB_ARGS_ANY());  /* 15.2.2.4.14 */
@@ -2352,13 +2297,19 @@
   mrb_define_method(mrb, mod, "const_get",               mrb_mod_const_get,        MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */
   mrb_define_method(mrb, mod, "const_set",               mrb_mod_const_set,        MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */
-  mrb_define_method(mrb, mod, "constants",               mrb_mod_constants,        MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
   mrb_define_method(mrb, mod, "remove_const",            mrb_mod_remove_const,     MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
   mrb_define_method(mrb, mod, "const_missing",           mrb_mod_const_missing,    MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, mod, "method_defined?",         mrb_mod_method_defined,   MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */
   mrb_define_method(mrb, mod, "define_method",           mod_define_method,        MRB_ARGS_ARG(1,1));
-  mrb_define_method(mrb, mod, "class_variables",         mrb_mod_class_variables,  MRB_ARGS_NONE()); /* 15.2.2.4.19 */
-  mrb_define_method(mrb, mod, "===",                     mrb_mod_eqq,              MRB_ARGS_REQ(1));
-  mrb_define_class_method(mrb, mod, "constants",         mrb_mod_s_constants,      MRB_ARGS_ANY());  /* 15.2.2.3.1 */
+  mrb_define_method(mrb, mod, "===",                     mrb_mod_eqq,              MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */
+  mrb_define_method(mrb, mod, "dup",                     mrb_mod_dup,              MRB_ARGS_NONE());
 
   mrb_undef_method(mrb, cls, "append_features");
+  mrb_undef_method(mrb, cls, "prepend_features");
   mrb_undef_method(mrb, cls, "extend_object");
-}
+  mrb_undef_method(mrb, cls, "module_function");
+
+  mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class);
+  mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE());
+  mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE());
+  mrb_define_singleton_method(mrb, mrb->top_self, "define_method", top_define_method, MRB_ARGS_ARG(1,1));
+}
