Index: EcnlProtoTool/trunk/mruby-2.1.1/src/array.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/src/array.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/src/array.c	(revision 439)
@@ -10,4 +10,6 @@
 #include <mruby/string.h>
 #include <mruby/range.h>
+#include <mruby/proc.h>
+#include <mruby/opcode.h>
 #include "value_array.h"
 
@@ -15,5 +17,5 @@
 #define ARY_SHRINK_RATIO  5 /* must be larger than 2 */
 #define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
-#define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
+#define ARY_MAX_SIZE ((mrb_int)((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? ARY_C_MAX_SIZE : MRB_INT_MAX-1))
 
 static struct RArray*
@@ -29,7 +31,12 @@
 
   a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
-  a->ptr = (mrb_value *)mrb_malloc(mrb, blen);
-  a->aux.capa = capa;
-  a->len = 0;
+  if (capa <= MRB_ARY_EMBED_LEN_MAX) {
+    ARY_SET_EMBED_LEN(a, 0);
+  }
+  else {
+    a->as.heap.ptr = (mrb_value *)mrb_malloc(mrb, blen);
+    a->as.heap.aux.capa = capa;
+    a->as.heap.len = 0;
+  }
 
   return a;
@@ -73,12 +80,19 @@
 }
 
+static struct RArray*
+ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
+{
+  struct RArray *a = ary_new_capa(mrb, size);
+
+  array_copy(ARY_PTR(a), vals, size);
+  ARY_SET_LEN(a, size);
+
+  return a;
+}
+
 MRB_API mrb_value
 mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
 {
-  struct RArray *a = ary_new_capa(mrb, size);
-
-  array_copy(a->ptr, vals, size);
-  a->len = size;
-
+  struct RArray *a = ary_new_from_values(mrb, size, vals);
   return mrb_obj_value(a);
 }
@@ -90,7 +104,7 @@
 
   a = ary_new_capa(mrb, 2);
-  a->ptr[0] = car;
-  a->ptr[1] = cdr;
-  a->len = 2;
+  ARY_PTR(a)[0] = car;
+  ARY_PTR(a)[1] = cdr;
+  ARY_SET_LEN(a, 2);
   return mrb_obj_value(a);
 }
@@ -107,16 +121,20 @@
 
 static void
+ary_modify_check(mrb_state *mrb, struct RArray *a)
+{
+  mrb_check_frozen(mrb, a);
+}
+
+static void
 ary_modify(mrb_state *mrb, struct RArray *a)
 {
-  if (MRB_FROZEN_P(a)) {
-    mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
-  }
+  ary_modify_check(mrb, a);
 
   if (ARY_SHARED_P(a)) {
-    mrb_shared_array *shared = a->aux.shared;
-
-    if (shared->refcnt == 1 && a->ptr == shared->ptr) {
-      a->ptr = shared->ptr;
-      a->aux.capa = a->len;
+    mrb_shared_array *shared = a->as.heap.aux.shared;
+
+    if (shared->refcnt == 1 && a->as.heap.ptr == shared->ptr) {
+      a->as.heap.ptr = shared->ptr;
+      a->as.heap.aux.capa = a->as.heap.len;
       mrb_free(mrb, shared);
     }
@@ -125,12 +143,12 @@
       mrb_int len;
 
-      p = a->ptr;
-      len = a->len * sizeof(mrb_value);
+      p = a->as.heap.ptr;
+      len = a->as.heap.len * sizeof(mrb_value);
       ptr = (mrb_value *)mrb_malloc(mrb, len);
       if (p) {
-        array_copy(ptr, p, a->len);
+        array_copy(ptr, p, a->as.heap.len);
       }
-      a->ptr = ptr;
-      a->aux.capa = a->len;
+      a->as.heap.ptr = ptr;
+      a->as.heap.aux.capa = a->as.heap.len;
       mrb_ary_decref(mrb, shared);
     }
@@ -149,16 +167,18 @@
 ary_make_shared(mrb_state *mrb, struct RArray *a)
 {
-  if (!ARY_SHARED_P(a)) {
+  if (!ARY_SHARED_P(a) && !ARY_EMBED_P(a)) {
     mrb_shared_array *shared = (mrb_shared_array *)mrb_malloc(mrb, sizeof(mrb_shared_array));
+    mrb_value *ptr = a->as.heap.ptr;
+    mrb_int len = a->as.heap.len;
 
     shared->refcnt = 1;
-    if (a->aux.capa > a->len) {
-      a->ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*a->len+1);
+    if (a->as.heap.aux.capa > len) {
+      a->as.heap.ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, ptr, sizeof(mrb_value)*len+1);
     }
     else {
-      shared->ptr = a->ptr;
-    }
-    shared->len = a->len;
-    a->aux.shared = shared;
+      shared->ptr = ptr;
+    }
+    shared->len = len;
+    a->as.heap.aux.shared = shared;
     ARY_SET_SHARED_FLAG(a);
   }
@@ -168,12 +188,12 @@
 ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
 {
-  mrb_int capa = a->aux.capa;
-
-  if (len > ARY_MAX_SIZE) {
+  mrb_int capa = ARY_CAPA(a);
+
+  if (len > ARY_MAX_SIZE || len < 0) {
   size_error:
     mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
   }
 
-  if (capa == 0) {
+  if (capa < ARY_DEFAULT_LEN) {
     capa = ARY_DEFAULT_LEN;
   }
@@ -190,9 +210,20 @@
   }
 
-  if (capa > a->aux.capa) {
-    mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
-
-    a->aux.capa = capa;
-    a->ptr = expanded_ptr;
+  if (ARY_EMBED_P(a)) {
+    mrb_value *ptr = ARY_EMBED_PTR(a);
+    mrb_int len = ARY_EMBED_LEN(a);
+    mrb_value *expanded_ptr = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*capa);
+
+    ARY_UNSET_EMBED_FLAG(a);
+    array_copy(expanded_ptr, ptr, len);
+    a->as.heap.len = len;
+    a->as.heap.aux.capa = capa;
+    a->as.heap.ptr = expanded_ptr;
+  }
+  else if (capa > a->as.heap.aux.capa) {
+    mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa);
+
+    a->as.heap.aux.capa = capa;
+    a->as.heap.ptr = expanded_ptr;
   }
 }
@@ -201,8 +232,12 @@
 ary_shrink_capa(mrb_state *mrb, struct RArray *a)
 {
-  mrb_int capa = a->aux.capa;
-
+
+  mrb_int capa;
+
+  if (ARY_EMBED_P(a)) return;
+
+  capa = a->as.heap.aux.capa;
   if (capa < ARY_DEFAULT_LEN * 2) return;
-  if (capa <= a->len * ARY_SHRINK_RATIO) return;
+  if (capa <= a->as.heap.len * ARY_SHRINK_RATIO) return;
 
   do {
@@ -212,9 +247,9 @@
       break;
     }
-  } while (capa > a->len * ARY_SHRINK_RATIO);
-
-  if (capa > a->len && capa < a->aux.capa) {
-    a->aux.capa = capa;
-    a->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
+  } while (capa > a->as.heap.len * ARY_SHRINK_RATIO);
+
+  if (capa > a->as.heap.len && capa < a->as.heap.aux.capa) {
+    a->as.heap.aux.capa = capa;
+    a->as.heap.ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa);
   }
 }
@@ -229,5 +264,4 @@
   old_len = RARRAY_LEN(ary);
   if (old_len != new_len) {
-    a->len = new_len;
     if (new_len < old_len) {
       ary_shrink_capa(mrb, a);
@@ -235,6 +269,7 @@
     else {
       ary_expand_capa(mrb, a, new_len);
-      ary_fill_with_nil(a->ptr + old_len, new_len - old_len);
-    }
+      ary_fill_with_nil(ARY_PTR(a) + old_len, new_len - old_len);
+    }
+    ARY_SET_LEN(a, new_len);
   }
 
@@ -250,5 +285,5 @@
   struct RArray *a;
 
-  mrb_get_args(mrb, "*", &vals, &len);
+  mrb_get_args(mrb, "*!", &vals, &len);
   ary = mrb_ary_new_from_values(mrb, len, vals);
   a = mrb_ary_ptr(ary);
@@ -258,4 +293,6 @@
 }
 
+static void ary_replace(mrb_state*, struct RArray*, struct RArray*);
+
 static void
 ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
@@ -263,16 +300,20 @@
   mrb_int len;
 
-  if (a2->len > ARY_MAX_SIZE - a->len) {
+  if (ARY_LEN(a) == 0) {
+    ary_replace(mrb, a, a2);
+    return;
+  }
+  if (ARY_LEN(a2) > ARY_MAX_SIZE - ARY_LEN(a)) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
   }
-  len = a->len + a2->len;
+  len = ARY_LEN(a) + ARY_LEN(a2);
 
   ary_modify(mrb, a);
-  if (a->aux.capa < len) {
+  if (ARY_CAPA(a) < len) {
     ary_expand_capa(mrb, a, len);
   }
-  array_copy(a->ptr+a->len, a2->ptr, a2->len);
+  array_copy(ARY_PTR(a)+ARY_LEN(a), ARY_PTR(a2), ARY_LEN(a2));
   mrb_write_barrier(mrb, (struct RBasic*)a);
-  a->len = len;
+  ARY_SET_LEN(a, len);
 }
 
@@ -301,27 +342,60 @@
   struct RArray *a2;
   mrb_value *ptr;
-  mrb_int blen;
+  mrb_int blen, len1;
 
   mrb_get_args(mrb, "a", &ptr, &blen);
-  if (ARY_MAX_SIZE - blen < a1->len) {
+  if (ARY_MAX_SIZE - blen < ARY_LEN(a1)) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
   }
-  a2 = ary_new_capa(mrb, a1->len + blen);
-  array_copy(a2->ptr, a1->ptr, a1->len);
-  array_copy(a2->ptr + a1->len, ptr, blen);
-  a2->len = a1->len + blen;
+  len1 = ARY_LEN(a1);
+  a2 = ary_new_capa(mrb, len1 + blen);
+  array_copy(ARY_PTR(a2), ARY_PTR(a1), len1);
+  array_copy(ARY_PTR(a2) + len1, ptr, blen);
+  ARY_SET_LEN(a2, len1+blen);
 
   return mrb_obj_value(a2);
 }
 
+#define ARY_REPLACE_SHARED_MIN 20
+
 static void
-ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
-{
-  ary_modify(mrb, a);
-  if (a->aux.capa < len)
+ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b)
+{
+  mrb_int len = ARY_LEN(b);
+
+  ary_modify_check(mrb, a);
+  if (a == b) return;
+  if (ARY_SHARED_P(a)) {
+    mrb_ary_decref(mrb, a->as.heap.aux.shared);
+    a->as.heap.aux.capa = 0;
+    a->as.heap.len = 0;
+    a->as.heap.ptr = NULL;
+    ARY_UNSET_SHARED_FLAG(a);
+  }
+  if (ARY_SHARED_P(b)) {
+  shared_b:
+    if (ARY_EMBED_P(a)) {
+      ARY_UNSET_EMBED_FLAG(a);
+    }
+    else {
+      mrb_free(mrb, a->as.heap.ptr);
+    }
+    a->as.heap.ptr = b->as.heap.ptr;
+    a->as.heap.len = len;
+    a->as.heap.aux.shared = b->as.heap.aux.shared;
+    a->as.heap.aux.shared->refcnt++;
+    ARY_SET_SHARED_FLAG(a);
+    mrb_write_barrier(mrb, (struct RBasic*)a);
+    return;
+  }
+  if (!mrb_frozen_p(b) && len > ARY_REPLACE_SHARED_MIN) {
+    ary_make_shared(mrb, b);
+    goto shared_b;
+  }
+  if (ARY_CAPA(a) < len)
     ary_expand_capa(mrb, a, len);
-  array_copy(a->ptr, argv, len);
+  array_copy(ARY_PTR(a), ARY_PTR(b), len);
   mrb_write_barrier(mrb, (struct RBasic*)a);
-  a->len = len;
+  ARY_SET_LEN(a, len);
 }
 
@@ -333,5 +407,5 @@
 
   if (a1 != a2) {
-    ary_replace(mrb, a1, a2->ptr, a2->len);
+    ary_replace(mrb, a1, a2);
   }
 }
@@ -354,5 +428,5 @@
   struct RArray *a2;
   mrb_value *ptr;
-  mrb_int times;
+  mrb_int times, len1;
 
   mrb_get_args(mrb, "i", &times);
@@ -361,13 +435,14 @@
   }
   if (times == 0) return mrb_ary_new(mrb);
-  if (ARY_MAX_SIZE / times < a1->len) {
+  if (ARY_MAX_SIZE / times < ARY_LEN(a1)) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
   }
-  a2 = ary_new_capa(mrb, a1->len * times);
-  ptr = a2->ptr;
+  len1 = ARY_LEN(a1);
+  a2 = ary_new_capa(mrb, len1 * times);
+  ARY_SET_LEN(a2, len1 * times);
+  ptr = ARY_PTR(a2);
   while (times--) {
-    array_copy(ptr, a1->ptr, a1->len);
-    ptr += a1->len;
-    a2->len += a1->len;
+    array_copy(ptr, ARY_PTR(a1), len1);
+    ptr += len1;
   }
 
@@ -379,11 +454,12 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
-
-  if (a->len > 1) {
+  mrb_int len = ARY_LEN(a);
+
+  if (len > 1) {
     mrb_value *p1, *p2;
 
     ary_modify(mrb, a);
-    p1 = a->ptr;
-    p2 = a->ptr + a->len - 1;
+    p1 = ARY_PTR(a);
+    p2 = p1 + len - 1;
 
     while (p1 < p2) {
@@ -399,16 +475,17 @@
 mrb_ary_reverse(mrb_state *mrb, mrb_value self)
 {
-  struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len);
-
-  if (a->len > 0) {
+  struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, ARY_LEN(a));
+  mrb_int len = ARY_LEN(a);
+
+  if (len > 0) {
     mrb_value *p1, *p2, *e;
 
-    p1 = a->ptr;
-    e  = p1 + a->len;
-    p2 = b->ptr + a->len - 1;
+    p1 = ARY_PTR(a);
+    e  = p1 + len;
+    p2 = ARY_PTR(b) + len - 1;
     while (p1 < e) {
       *p2-- = *p1++;
     }
-    b->len = a->len;
+    ARY_SET_LEN(b, len);
   }
   return mrb_obj_value(b);
@@ -419,9 +496,11 @@
 {
   struct RArray *a = mrb_ary_ptr(ary);
+  mrb_int len = ARY_LEN(a);
 
   ary_modify(mrb, a);
-  if (a->len == a->aux.capa)
-    ary_expand_capa(mrb, a, a->len + 1);
-  a->ptr[a->len++] = elem;
+  if (len == ARY_CAPA(a))
+    ary_expand_capa(mrb, a, len + 1);
+  ARY_PTR(a)[len] = elem;
+  ARY_SET_LEN(a, len+1);
   mrb_field_write_barrier_value(mrb, (struct RBasic*)a, elem);
 }
@@ -431,10 +510,18 @@
 {
   mrb_value *argv;
-  mrb_int len;
-
-  mrb_get_args(mrb, "*", &argv, &len);
-  while (len--) {
-    mrb_ary_push(mrb, self, *argv++);
-  }
+  mrb_int len, len2, alen;
+  struct RArray *a;
+
+  mrb_get_args(mrb, "*!", &argv, &alen);
+  a = mrb_ary_ptr(self);
+  ary_modify(mrb, a);
+  len = ARY_LEN(a);
+  len2 = len + alen;
+  if (ARY_CAPA(a) < len2) {
+    ary_expand_capa(mrb, a, len2);
+  }
+  array_copy(ARY_PTR(a)+len, argv, alen);
+  ARY_SET_LEN(a, len2);
+  mrb_write_barrier(mrb, (struct RBasic*)a);
 
   return self;
@@ -445,8 +532,10 @@
 {
   struct RArray *a = mrb_ary_ptr(ary);
-
-  ary_modify(mrb, a);
-  if (a->len == 0) return mrb_nil_value();
-  return a->ptr[--a->len];
+  mrb_int len = ARY_LEN(a);
+
+  ary_modify_check(mrb, a);
+  if (len == 0) return mrb_nil_value();
+  ARY_SET_LEN(a, len-1);
+  return ARY_PTR(a)[len-1];
 }
 
@@ -457,22 +546,23 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
+  mrb_int len = ARY_LEN(a);
   mrb_value val;
 
-  ary_modify(mrb, a);
-  if (a->len == 0) return mrb_nil_value();
+  ary_modify_check(mrb, a);
+  if (len == 0) return mrb_nil_value();
   if (ARY_SHARED_P(a)) {
   L_SHIFT:
-    val = a->ptr[0];
-    a->ptr++;
-    a->len--;
+    val = a->as.heap.ptr[0];
+    a->as.heap.ptr++;
+    a->as.heap.len--;
     return val;
   }
-  if (a->len > ARY_SHIFT_SHARED_MIN) {
+  if (len > ARY_SHIFT_SHARED_MIN) {
     ary_make_shared(mrb, a);
     goto L_SHIFT;
   }
   else {
-    mrb_value *ptr = a->ptr;
-    mrb_int size = a->len;
+    mrb_value *ptr = ARY_PTR(a);
+    mrb_int size = len;
 
     val = *ptr;
@@ -481,5 +571,5 @@
       ++ptr;
     }
-    --a->len;
+    ARY_SET_LEN(a, len-1);
   }
   return val;
@@ -494,19 +584,23 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
+  mrb_int len = ARY_LEN(a);
 
   if (ARY_SHARED_P(a)
-      && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
-      && a->ptr - a->aux.shared->ptr >= 1) /* there's room for unshifted item */ {
-    a->ptr--;
-    a->ptr[0] = item;
+      && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */
+      && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= 1) /* there's room for unshifted item */ {
+    a->as.heap.ptr--;
+    a->as.heap.ptr[0] = item;
   }
   else {
+    mrb_value *ptr;
+
     ary_modify(mrb, a);
-    if (a->aux.capa < a->len + 1)
-      ary_expand_capa(mrb, a, a->len + 1);
-    value_move(a->ptr + 1, a->ptr, a->len);
-    a->ptr[0] = item;
-  }
-  a->len++;
+    if (ARY_CAPA(a) < len + 1)
+      ary_expand_capa(mrb, a, len + 1);
+    ptr = ARY_PTR(a);
+    value_move(ptr + 1, ptr, len);
+    ptr[0] = item;
+  }
+  ARY_SET_LEN(a, len+1);
   mrb_field_write_barrier_value(mrb, (struct RBasic*)a, item);
 
@@ -518,27 +612,36 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
-  mrb_value *vals;
-  mrb_int len;
-
-  mrb_get_args(mrb, "*", &vals, &len);
-  if (len > ARY_MAX_SIZE - a->len) {
+  mrb_value *vals, *ptr;
+  mrb_int alen, len;
+
+  mrb_get_args(mrb, "*!", &vals, &alen);
+  if (alen == 0) {
+    ary_modify_check(mrb, a);
+    return self;
+  }
+  len = ARY_LEN(a);
+  if (alen > ARY_MAX_SIZE - len) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
   }
   if (ARY_SHARED_P(a)
-      && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
-      && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ {
-    a->ptr -= len;
+      && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */
+      && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= alen) /* there's room for unshifted item */ {
+    ary_modify_check(mrb, a);
+    a->as.heap.ptr -= alen;
+    ptr = a->as.heap.ptr;
   }
   else {
+    mrb_bool same = vals == ARY_PTR(a);
     ary_modify(mrb, a);
-    if (len == 0) return self;
-    if (a->aux.capa < a->len + len)
-      ary_expand_capa(mrb, a, a->len + len);
-    value_move(a->ptr + len, a->ptr, a->len);
-  }
-  array_copy(a->ptr, vals, len);
-  a->len += len;
-  while (len--) {
-    mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[len]);
+    if (ARY_CAPA(a) < len + alen)
+      ary_expand_capa(mrb, a, len + alen);
+    ptr = ARY_PTR(a);
+    value_move(ptr + alen, ptr, len);
+    if (same) vals = ptr;
+  }
+  array_copy(ptr, vals, alen);
+  ARY_SET_LEN(a, len+alen);
+  while (alen--) {
+    mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[alen]);
   }
 
@@ -550,10 +653,11 @@
 {
   struct RArray *a = mrb_ary_ptr(ary);
+  mrb_int len = ARY_LEN(a);
 
   /* range check */
-  if (n < 0) n += a->len;
-  if (n < 0 || a->len <= n) return mrb_nil_value();
-
-  return a->ptr[n];
+  if (n < 0) n += len;
+  if (n < 0 || len <= n) return mrb_nil_value();
+
+  return ARY_PTR(a)[n];
 }
 
@@ -562,21 +666,22 @@
 {
   struct RArray *a = mrb_ary_ptr(ary);
+  mrb_int len = ARY_LEN(a);
 
   ary_modify(mrb, a);
   /* range check */
   if (n < 0) {
-    n += a->len;
+    n += len;
     if (n < 0) {
-      mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - a->len));
-    }
-  }
-  if (a->len <= n) {
-    if (a->aux.capa <= n)
+      mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of array", n - len);
+    }
+  }
+  if (len <= n) {
+    if (ARY_CAPA(a) <= n)
       ary_expand_capa(mrb, a, n + 1);
-    ary_fill_with_nil(a->ptr + a->len, n + 1 - a->len);
-    a->len = n + 1;
-  }
-
-  a->ptr[n] = val;
+    ary_fill_with_nil(ARY_PTR(a) + len, n + 1 - len);
+    ARY_SET_LEN(a, n+1);
+  }
+
+  ARY_PTR(a)[n] = val;
   mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
 }
@@ -585,8 +690,5 @@
 ary_dup(mrb_state *mrb, struct RArray *a)
 {
-  struct RArray *d = ary_new_capa(mrb, a->len);
-
-  ary_replace(mrb, d, a->ptr, a->len);
-  return d;
+  return ary_new_from_values(mrb, ARY_LEN(a), ARY_PTR(a));
 }
 
@@ -595,4 +697,5 @@
 {
   struct RArray *a = mrb_ary_ptr(ary);
+  mrb_int alen = ARY_LEN(a);
   const mrb_value *argv;
   mrb_int argc;
@@ -602,9 +705,9 @@
 
   /* len check */
-  if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len));
+  if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%i)", len);
 
   /* range check */
   if (head < 0) {
-    head += a->len;
+    head += alen;
     if (head < 0) {
       mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
@@ -612,6 +715,6 @@
   }
   tail = head + len;
-  if (a->len < len || a->len < tail) {
-    len = a->len - head;
+  if (alen < len || alen < tail) {
+    len = alen - head;
   }
 
@@ -620,5 +723,5 @@
     argc = RARRAY_LEN(rpl);
     argv = RARRAY_PTR(rpl);
-    if (argv == a->ptr) {
+    if (argv == ARY_PTR(a)) {
       struct RArray *r;
 
@@ -627,5 +730,5 @@
       }
       r = ary_dup(mrb, a);
-      argv = r->ptr;
+      argv = ARY_PTR(r);
     }
   }
@@ -634,36 +737,37 @@
     argv = &rpl;
   }
-  if (head >= a->len) {
+  if (head >= alen) {
     if (head > ARY_MAX_SIZE - argc) {
-      mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
+      mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head);
     }
     len = head + argc;
-    if (len > a->aux.capa) {
+    if (len > ARY_CAPA(a)) {
       ary_expand_capa(mrb, a, head + argc);
     }
-    ary_fill_with_nil(a->ptr + a->len, head - a->len);
+    ary_fill_with_nil(ARY_PTR(a) + alen, head - alen);
     if (argc > 0) {
-      array_copy(a->ptr + head, argv, argc);
-    }
-    a->len = len;
+      array_copy(ARY_PTR(a) + head, argv, argc);
+    }
+    ARY_SET_LEN(a, len);
   }
   else {
-    mrb_int alen;
-
-    if (a->len - len > ARY_MAX_SIZE - argc) {
-      mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len));
-    }
-    alen = a->len + argc - len;
-    if (alen > a->aux.capa) {
-      ary_expand_capa(mrb, a, alen);
+    mrb_int newlen;
+
+    if (alen - len > ARY_MAX_SIZE - argc) {
+      mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", alen + argc - len);
+    }
+    newlen = alen + argc - len;
+    if (newlen > ARY_CAPA(a)) {
+      ary_expand_capa(mrb, a, newlen);
     }
 
     if (len != argc) {
+      mrb_value *ptr = ARY_PTR(a);
       tail = head + len;
-      value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
-      a->len = alen;
+      value_move(ptr + head + argc, ptr + tail, alen - tail);
+      ARY_SET_LEN(a, newlen);
     }
     if (argc > 0) {
-      value_move(a->ptr + head, argv, argc);
+      value_move(ARY_PTR(a) + head, argv, argc);
     }
   }
@@ -687,10 +791,13 @@
   struct RArray *b;
 
+  if (!ARY_SHARED_P(a) && len <= ARY_SHIFT_SHARED_MIN) {
+    return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg);
+  }
   ary_make_shared(mrb, a);
   b  = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
-  b->ptr = a->ptr + beg;
-  b->len = len;
-  b->aux.shared = a->aux.shared;
-  b->aux.shared->refcnt++;
+  b->as.heap.ptr = a->as.heap.ptr + beg;
+  b->as.heap.len = len;
+  b->as.heap.aux.shared = a->as.heap.aux.shared;
+  b->as.heap.aux.shared->refcnt++;
   ARY_SET_SHARED_FLAG(b);
 
@@ -704,12 +811,14 @@
     return mrb_fixnum(index);
   }
+#ifndef MRB_WITHOUT_FLOAT
   else if (mrb_float_p(index)) {
     return (mrb_int)mrb_float(index);
   }
+#endif
   else {
     mrb_int i, argc;
     mrb_value *argv;
 
-    mrb_get_args(mrb, "i*", &i, &argv, &argc);
+    mrb_get_args(mrb, "i*!", &i, &argv, &argc);
     return i;
   }
@@ -747,5 +856,5 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
-  mrb_int i, len;
+  mrb_int i, len, alen;
   mrb_value index;
 
@@ -754,5 +863,5 @@
       /* a[n..m] */
     case MRB_TT_RANGE:
-      if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
+      if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) {
         return ary_subseq(mrb, a, i, len);
       }
@@ -768,9 +877,10 @@
 
   i = aget_index(mrb, index);
-  if (i < 0) i += a->len;
-  if (i < 0 || a->len < i) return mrb_nil_value();
+  alen = ARY_LEN(a);
+  if (i < 0) i += alen;
+  if (i < 0 || alen < i) return mrb_nil_value();
   if (len < 0) return mrb_nil_value();
-  if (a->len == i) return mrb_ary_new(mrb);
-  if (len > a->len - i) len = a->len - i;
+  if (alen == i) return mrb_ary_new(mrb);
+  if (len > alen - i) len = alen - i;
 
   return ary_subseq(mrb, a, i, len);
@@ -822,12 +932,12 @@
     /* a[n..m] = v */
     switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) {
-    case 0:                   /* not range */
+    case MRB_RANGE_TYPE_MISMATCH:
       mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
       break;
-    case 1:                   /* range */
+    case MRB_RANGE_OK:
       mrb_ary_splice(mrb, self, i, len, v2);
       break;
-    case 2:                   /* out of range */
-      mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1);
+    case MRB_RANGE_OUT:
+      mrb_raisef(mrb, E_RANGE_ERROR, "%v out of range", v1);
       break;
     }
@@ -847,20 +957,22 @@
   mrb_value val;
   mrb_value *ptr;
-  mrb_int len;
+  mrb_int len, alen;
 
   mrb_get_args(mrb, "i", &index);
-  if (index < 0) index += a->len;
-  if (index < 0 || a->len <= index) return mrb_nil_value();
+  alen = ARY_LEN(a);
+  if (index < 0) index += alen;
+  if (index < 0 || alen <= index) return mrb_nil_value();
 
   ary_modify(mrb, a);
-  val = a->ptr[index];
-
-  ptr = a->ptr + index;
-  len = a->len - index;
+  ptr = ARY_PTR(a);
+  val = ptr[index];
+
+  ptr += index;
+  len = alen - index;
   while (--len) {
     *ptr = *(ptr+1);
     ++ptr;
   }
-  --a->len;
+  ARY_SET_LEN(a, alen-1);
 
   ary_shrink_capa(mrb, a);
@@ -873,18 +985,20 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
-  mrb_int size;
-
-  if (mrb_get_args(mrb, "|i", &size) == 0) {
-    return (a->len > 0)? a->ptr[0]: mrb_nil_value();
-  }
+  mrb_int size, alen;
+
+  if (mrb_get_argc(mrb) == 0) {
+    return (ARY_LEN(a) > 0)? ARY_PTR(a)[0]: mrb_nil_value();
+  }
+  mrb_get_args(mrb, "|i", &size);
   if (size < 0) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
   }
 
-  if (size > a->len) size = a->len;
+  alen = ARY_LEN(a);
+  if (size > alen) size = alen;
   if (ARY_SHARED_P(a)) {
     return ary_subseq(mrb, a, 0, size);
   }
-  return mrb_ary_new_from_values(mrb, size, a->ptr);
+  return mrb_ary_new_from_values(mrb, size, ARY_PTR(a));
 }
 
@@ -893,17 +1007,20 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
-  mrb_int size;
-
-  if (mrb_get_args(mrb, "|i", &size) == 0)
-    return (a->len > 0)? a->ptr[a->len - 1]: mrb_nil_value();
+  mrb_int n, size, alen;
+
+  n = mrb_get_args(mrb, "|i", &size);
+  alen = ARY_LEN(a);
+  if (n == 0) {
+    return (alen > 0) ? ARY_PTR(a)[alen - 1]: mrb_nil_value();
+  }
 
   if (size < 0) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
   }
-  if (size > a->len) size = a->len;
+  if (size > alen) size = alen;
   if (ARY_SHARED_P(a) || size > ARY_DEFAULT_LEN) {
-    return ary_subseq(mrb, a, a->len - size, size);
-  }
-  return mrb_ary_new_from_values(mrb, size, a->ptr + a->len - size);
+    return ary_subseq(mrb, a, alen - size, size);
+  }
+  return mrb_ary_new_from_values(mrb, size, ARY_PTR(a) + alen - size);
 }
 
@@ -944,5 +1061,5 @@
 mrb_ary_splat(mrb_state *mrb, mrb_value v)
 {
-  mrb_value a, recv_class;
+  mrb_value a;
 
   if (mrb_array_p(v)) {
@@ -955,20 +1072,9 @@
 
   a = mrb_funcall(mrb, v, "to_a", 0);
-  if (mrb_array_p(a)) {
-    return a;
-  }
-  else if (mrb_nil_p(a)) {
+  if (mrb_nil_p(a)) {
     return mrb_ary_new_from_values(mrb, 1, &v);
   }
-  else {
-    recv_class = mrb_obj_value(mrb_obj_class(mrb, v));
-    mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)",
-      recv_class,
-      recv_class,
-      mrb_obj_value(mrb_obj_class(mrb, a))
-    );
-    /* not reached */
-    return mrb_undef_value();
-  }
+  mrb_ensure_array_type(mrb, a);
+  return a;
 }
 
@@ -978,5 +1084,5 @@
   struct RArray *a = mrb_ary_ptr(self);
 
-  return mrb_fixnum_value(a->len);
+  return mrb_fixnum_value(ARY_LEN(a));
 }
 
@@ -988,13 +1094,11 @@
   ary_modify(mrb, a);
   if (ARY_SHARED_P(a)) {
-    mrb_ary_decref(mrb, a->aux.shared);
+    mrb_ary_decref(mrb, a->as.heap.aux.shared);
     ARY_UNSET_SHARED_FLAG(a);
   }
-  else {
-    mrb_free(mrb, a->ptr);
-  }
-  a->len = 0;
-  a->aux.capa = 0;
-  a->ptr = 0;
+  else if (!ARY_EMBED_P(a)){
+    mrb_free(mrb, a->as.heap.ptr);
+  }
+  ARY_SET_EMBED_LEN(a, 0);
 
   return self;
@@ -1002,15 +1106,15 @@
 
 static mrb_value
+mrb_ary_clear_m(mrb_state *mrb, mrb_value self)
+{
+  return mrb_ary_clear(mrb, self);
+}
+
+static mrb_value
 mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
 {
   struct RArray *a = mrb_ary_ptr(self);
 
-  return mrb_bool_value(a->len == 0);
-}
-
-MRB_API mrb_value
-mrb_check_array_type(mrb_state *mrb, mrb_value ary)
-{
-  return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
+  return mrb_bool_value(ARY_LEN(a) == 0);
 }
 
@@ -1021,5 +1125,8 @@
     offset += RARRAY_LEN(ary);
   }
-  return ary_elt(ary, offset);
+  if (offset < 0 || RARRAY_LEN(ary) <= offset) {
+    return mrb_nil_value();
+  }
+  return RARRAY_PTR(ary)[offset];
 }
 
@@ -1039,5 +1146,5 @@
   mrb_ary_push(mrb, list, ary);
 
-  result = mrb_str_buf_new(mrb, 64);
+  result = mrb_str_new_capa(mrb, 64);
 
   for (i=0; i<RARRAY_LEN(ary); i++) {
@@ -1065,5 +1172,5 @@
           goto str_join;
         }
-        tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
+        tmp = mrb_check_array_type(mrb, val);
         if (!mrb_nil_p(tmp)) {
           val = tmp;
@@ -1139,4 +1246,68 @@
 }
 
+/* internal method to convert multi-value to single value */
+static mrb_value
+mrb_ary_svalue(mrb_state *mrb, mrb_value ary)
+{
+  switch (RARRAY_LEN(ary)) {
+  case 0:
+    return mrb_nil_value();
+  case 1:
+    return RARRAY_PTR(ary)[0];
+  default:
+    return ary;
+  }
+}
+
+static const mrb_code each_iseq[] = {
+  OP_ENTER, 0x0, 0x00, 0x1,  /* OP_ENTER     0:0:0:0:0:0:1 */
+  OP_JMPIF, 0x1, 0x0, 19,    /* OP_JMPIF     R1  19 */
+  OP_LOADSELF, 0x3,          /* OP_LOADSELF  R3 */
+  OP_LOADSYM, 0x4, 0x0,      /* OP_LOADSYM   R4  :each*/
+  OP_SEND, 0x3, 0x1, 0x1,    /* OP_SEND      R3  :to_enum   1 */
+  OP_RETURN, 0x3,            /* OP_RETURN    R3 */
+  OP_LOADI_0, 0x2,           /* OP_LOADI_0   R2 */
+  OP_JMP, 0x0, 43,           /* OP_JMP       49 */
+  OP_MOVE, 0x3, 0x1,         /* OP_MOVE      R3  R1 */
+  OP_LOADSELF, 0x4,          /* OP_LOADSELF  R4 */
+  OP_MOVE, 0x5, 0x2,         /* OP_MOVE      R5  R2 */
+  OP_SEND, 0x4, 0x2, 0x1,    /* OP_SEND      R4  :[]        1 */
+  OP_SEND, 0x3, 0x3, 0x1,    /* OP_SEND      R3  :call      1 */
+  OP_ADDI, 0x2, 1,           /* OP_ADDI      R3  1 */
+  OP_MOVE, 0x3, 0x2,         /* OP_MOVE      R3  R2 */
+  OP_LOADSELF, 0x4,          /* OP_LOADSELF  R4 */
+  OP_SEND, 0x4, 0x4, 0x0,    /* OP_SEND      R4  :length    0 */
+  OP_LT, 0x3,                /* OP_LT        R3 */
+  OP_JMPIF, 0x3, 0x0, 24,    /* OP_JMPIF     R3  24 */
+  OP_RETURN, 0x0             /* OP_RETURN    R3 */
+};
+
+static void
+init_ary_each(mrb_state *mrb, struct RClass *ary)
+{
+  struct RProc *p;
+  mrb_method_t m;
+  mrb_irep *each_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep));
+  static const mrb_irep mrb_irep_zero = { 0 };
+
+  *each_irep = mrb_irep_zero;
+  each_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*5);
+  each_irep->syms[0] = mrb_intern_lit(mrb, "each");
+  each_irep->syms[1] = mrb_intern_lit(mrb, "to_enum");
+  each_irep->syms[2] = mrb_intern_lit(mrb, "[]");
+  each_irep->syms[3] = mrb_intern_lit(mrb, "call");
+  each_irep->syms[4] = mrb_intern_lit(mrb, "length");
+  each_irep->slen = 5;
+  each_irep->flags = MRB_ISEQ_NO_FREE;
+  each_irep->iseq = each_iseq;
+  each_irep->ilen = sizeof(each_iseq);
+  each_irep->nregs = 7;
+  each_irep->nlocals = 3;
+  p = mrb_proc_new(mrb, each_irep);
+  p->flags |= MRB_PROC_SCOPE | MRB_PROC_STRICT;
+  MRB_METHOD_FROM_PROC(m, p);
+  mrb_define_method_raw(mrb, ary, mrb_intern_lit(mrb, "each"), m);
+}
+
 void
 mrb_init_array(mrb_state *mrb)
@@ -1144,39 +1315,40 @@
   struct RClass *a;
 
-  mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class);            /* 15.2.12 */
+  mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class);              /* 15.2.12 */
   MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY);
 
-  mrb_define_class_method(mrb, a, "[]",        mrb_ary_s_create,     MRB_ARGS_ANY());  /* 15.2.12.4.1 */
-
-  mrb_define_method(mrb, a, "+",               mrb_ary_plus,         MRB_ARGS_REQ(1)); /* 15.2.12.5.1  */
-  mrb_define_method(mrb, a, "*",               mrb_ary_times,        MRB_ARGS_REQ(1)); /* 15.2.12.5.2  */
-  mrb_define_method(mrb, a, "<<",              mrb_ary_push_m,       MRB_ARGS_REQ(1)); /* 15.2.12.5.3  */
-  mrb_define_method(mrb, a, "[]",              mrb_ary_aget,         MRB_ARGS_ANY());  /* 15.2.12.5.4  */
-  mrb_define_method(mrb, a, "[]=",             mrb_ary_aset,         MRB_ARGS_ANY());  /* 15.2.12.5.5  */
-  mrb_define_method(mrb, a, "clear",           mrb_ary_clear,        MRB_ARGS_NONE()); /* 15.2.12.5.6  */
-  mrb_define_method(mrb, a, "concat",          mrb_ary_concat_m,     MRB_ARGS_REQ(1)); /* 15.2.12.5.8  */
-  mrb_define_method(mrb, a, "delete_at",       mrb_ary_delete_at,    MRB_ARGS_REQ(1)); /* 15.2.12.5.9  */
-  mrb_define_method(mrb, a, "empty?",          mrb_ary_empty_p,      MRB_ARGS_NONE()); /* 15.2.12.5.12 */
-  mrb_define_method(mrb, a, "first",           mrb_ary_first,        MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */
-  mrb_define_method(mrb, a, "index",           mrb_ary_index_m,      MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */
-  mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m,    MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */
-  mrb_define_method(mrb, a, "join",            mrb_ary_join_m,       MRB_ARGS_ANY());  /* 15.2.12.5.17 */
-  mrb_define_method(mrb, a, "last",            mrb_ary_last,         MRB_ARGS_ANY());  /* 15.2.12.5.18 */
-  mrb_define_method(mrb, a, "length",          mrb_ary_size,         MRB_ARGS_NONE()); /* 15.2.12.5.19 */
-  mrb_define_method(mrb, a, "pop",             mrb_ary_pop,          MRB_ARGS_NONE()); /* 15.2.12.5.21 */
-  mrb_define_method(mrb, a, "push",            mrb_ary_push_m,       MRB_ARGS_ANY());  /* 15.2.12.5.22 */
-  mrb_define_method(mrb, a, "append",          mrb_ary_push_m,       MRB_ARGS_ANY());
-  mrb_define_method(mrb, a, "replace",         mrb_ary_replace_m,    MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
-  mrb_define_method(mrb, a, "reverse",         mrb_ary_reverse,      MRB_ARGS_NONE()); /* 15.2.12.5.24 */
-  mrb_define_method(mrb, a, "reverse!",        mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
-  mrb_define_method(mrb, a, "rindex",          mrb_ary_rindex_m,     MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */
-  mrb_define_method(mrb, a, "shift",           mrb_ary_shift,        MRB_ARGS_NONE()); /* 15.2.12.5.27 */
-  mrb_define_method(mrb, a, "size",            mrb_ary_size,         MRB_ARGS_NONE()); /* 15.2.12.5.28 */
-  mrb_define_method(mrb, a, "slice",           mrb_ary_aget,         MRB_ARGS_ANY());  /* 15.2.12.5.29 */
-  mrb_define_method(mrb, a, "unshift",         mrb_ary_unshift_m,    MRB_ARGS_ANY());  /* 15.2.12.5.30 */
-  mrb_define_method(mrb, a, "prepend",         mrb_ary_unshift_m,    MRB_ARGS_ANY());
+  mrb_define_class_method(mrb, a, "[]",        mrb_ary_s_create,     MRB_ARGS_ANY());    /* 15.2.12.4.1 */
+
+  mrb_define_method(mrb, a, "+",               mrb_ary_plus,         MRB_ARGS_REQ(1));   /* 15.2.12.5.1  */
+  mrb_define_method(mrb, a, "*",               mrb_ary_times,        MRB_ARGS_REQ(1));   /* 15.2.12.5.2  */
+  mrb_define_method(mrb, a, "<<",              mrb_ary_push_m,       MRB_ARGS_REQ(1));   /* 15.2.12.5.3  */
+  mrb_define_method(mrb, a, "[]",              mrb_ary_aget,         MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4  */
+  mrb_define_method(mrb, a, "[]=",             mrb_ary_aset,         MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5  */
+  mrb_define_method(mrb, a, "clear",           mrb_ary_clear_m,      MRB_ARGS_NONE());   /* 15.2.12.5.6  */
+  mrb_define_method(mrb, a, "concat",          mrb_ary_concat_m,     MRB_ARGS_REQ(1));   /* 15.2.12.5.8  */
+  mrb_define_method(mrb, a, "delete_at",       mrb_ary_delete_at,    MRB_ARGS_REQ(1));   /* 15.2.12.5.9  */
+  mrb_define_method(mrb, a, "empty?",          mrb_ary_empty_p,      MRB_ARGS_NONE());   /* 15.2.12.5.12 */
+  mrb_define_method(mrb, a, "first",           mrb_ary_first,        MRB_ARGS_OPT(1));   /* 15.2.12.5.13 */
+  mrb_define_method(mrb, a, "index",           mrb_ary_index_m,      MRB_ARGS_REQ(1));   /* 15.2.12.5.14 */
+  mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m,    MRB_ARGS_REQ(1));   /* 15.2.12.5.16 */
+  mrb_define_method(mrb, a, "join",            mrb_ary_join_m,       MRB_ARGS_OPT(1));   /* 15.2.12.5.17 */
+  mrb_define_method(mrb, a, "last",            mrb_ary_last,         MRB_ARGS_OPT(1));   /* 15.2.12.5.18 */
+  mrb_define_method(mrb, a, "length",          mrb_ary_size,         MRB_ARGS_NONE());   /* 15.2.12.5.19 */
+  mrb_define_method(mrb, a, "pop",             mrb_ary_pop,          MRB_ARGS_NONE());   /* 15.2.12.5.21 */
+  mrb_define_method(mrb, a, "push",            mrb_ary_push_m,       MRB_ARGS_ANY());    /* 15.2.12.5.22 */
+  mrb_define_method(mrb, a, "replace",         mrb_ary_replace_m,    MRB_ARGS_REQ(1));   /* 15.2.12.5.23 */
+  mrb_define_method(mrb, a, "reverse",         mrb_ary_reverse,      MRB_ARGS_NONE());   /* 15.2.12.5.24 */
+  mrb_define_method(mrb, a, "reverse!",        mrb_ary_reverse_bang, MRB_ARGS_NONE());   /* 15.2.12.5.25 */
+  mrb_define_method(mrb, a, "rindex",          mrb_ary_rindex_m,     MRB_ARGS_REQ(1));   /* 15.2.12.5.26 */
+  mrb_define_method(mrb, a, "shift",           mrb_ary_shift,        MRB_ARGS_NONE());   /* 15.2.12.5.27 */
+  mrb_define_method(mrb, a, "size",            mrb_ary_size,         MRB_ARGS_NONE());   /* 15.2.12.5.28 */
+  mrb_define_method(mrb, a, "slice",           mrb_ary_aget,         MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */
+  mrb_define_method(mrb, a, "unshift",         mrb_ary_unshift_m,    MRB_ARGS_ANY());    /* 15.2.12.5.30 */
 
   mrb_define_method(mrb, a, "__ary_eq",        mrb_ary_eq,           MRB_ARGS_REQ(1));
   mrb_define_method(mrb, a, "__ary_cmp",       mrb_ary_cmp,          MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, a, "__ary_index",     mrb_ary_index_m,      MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */
-}
+  mrb_define_method(mrb, a, "__ary_index",     mrb_ary_index_m,      MRB_ARGS_REQ(1));   /* kept for mruby-array-ext */
+  mrb_define_method(mrb, a, "__svalue",        mrb_ary_svalue,       MRB_ARGS_NONE());
+
+  init_ary_each(mrb, a);
+}
