summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-07-27 12:46:51 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-07-27 16:13:06 +0900
commitf26d00d9e81b102fababdd9c0d1b886fab30e35a (patch)
tree057788919d060adb7d0045ef6a67cd0a7ae63d8f
parent5d44f8582eb2f3011145861692d9ad42975f7a74 (diff)
downloadmruby-f26d00d9e81b102fababdd9c0d1b886fab30e35a.tar.gz
mruby-f26d00d9e81b102fababdd9c0d1b886fab30e35a.zip
Embed small size array elements in the heap.
It reduces the memory consumption and sometimes improve the performance as well. For example, the consumed memory size of `bench/bm_ao_render.rb` is reduced from 1.2GB to 1GB, and its total execution time become 18.795 sec from 22.229 sec.
-rw-r--r--include/mruby/array.h40
-rw-r--r--mrbgems/mruby-array-ext/src/array.c22
-rw-r--r--mrbgems/mruby-random/src/random.c8
-rw-r--r--mrbgems/mruby-struct/src/struct.c4
-rw-r--r--src/array.c385
-rw-r--r--src/class.c18
-rw-r--r--src/gc.c23
-rw-r--r--src/hash.c2
-rw-r--r--src/vm.c28
9 files changed, 304 insertions, 226 deletions
diff --git a/include/mruby/array.h b/include/mruby/array.h
index e553faf92..bd3124d8c 100644
--- a/include/mruby/array.h
+++ b/include/mruby/array.h
@@ -21,22 +21,48 @@ typedef struct mrb_shared_array {
mrb_value *ptr;
} mrb_shared_array;
+#define MRB_ARY_EMBED_LEN_MAX ((mrb_int)(sizeof(void*)*3/sizeof(mrb_value)))
struct RArray {
MRB_OBJECT_HEADER;
- mrb_int len;
union {
- mrb_int capa;
- mrb_shared_array *shared;
- } aux;
- mrb_value *ptr;
+ struct {
+ mrb_int len;
+ union {
+ mrb_int capa;
+ mrb_shared_array *shared;
+ } aux;
+ mrb_value *ptr;
+ } heap;
+ mrb_value embed[MRB_ARY_EMBED_LEN_MAX];
+ } as;
};
#define mrb_ary_ptr(v) ((struct RArray*)(mrb_ptr(v)))
#define mrb_ary_value(p) mrb_obj_value((void*)(p))
#define RARRAY(v) ((struct RArray*)(mrb_ptr(v)))
-#define RARRAY_LEN(a) (RARRAY(a)->len)
-#define RARRAY_PTR(a) ((const mrb_value*)RARRAY(a)->ptr)
+#define MRB_ARY_EMBED 4
+#define MRB_ARY_EMBED_MASK 3
+#define ARY_EMBED_P(a) ((a)->flags & MRB_ARY_EMBED)
+#define ARY_SET_EMBED_FLAG(a) ((a)->flags |= MRB_ARY_EMBED)
+#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED|MRB_ARY_EMBED_MASK))
+#define ARY_EMBED_LEN(a) ((a)->flags & MRB_ARY_EMBED_MASK)
+#define ARY_SET_EMBED_LEN(a,len) (a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((len)&MRB_ARY_EMBED_MASK);
+#define ARY_EMBED_PTR(a) (&((a)->as.embed[0]))
+
+#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len)
+#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
+#define RARRAY_LEN(a) ARY_LEN(RARRAY(a))
+#define RARRAY_PTR(a) ARY_PTR(RARRAY(a))
+#define ARY_SET_LEN(a,n) do {\
+ if (ARY_EMBED_P(a)) {\
+ mrb_assert((n) <= MRB_ARY_EMBED_LEN_MAX); \
+ ARY_SET_EMBED_LEN(a,n);\
+ }\
+ else\
+ (a)->as.heap.len = (n);\
+} while (0)
+#define ARY_CAPA(a) (ARY_EMBED_P(a)?MRB_ARY_EMBED_LEN_MAX:(a)->as.heap.aux.capa)
#define MRB_ARY_SHARED 256
#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED)
#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED)
diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c
index 6919186bd..72e5080f1 100644
--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -174,7 +174,7 @@ static mrb_value
mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int i, j, k, len;
+ mrb_int i, j, k, len, alen = ARY_LEN(a);
mrb_value index;
mrb_value val;
mrb_value *ptr;
@@ -185,7 +185,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
switch (mrb_type(index)) {
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, alen, TRUE) == 1) {
goto delete_pos_len;
}
else {
@@ -202,25 +202,25 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
i = mrb_fixnum(index);
delete_pos_len:
- if (i < 0) i += a->len;
- if (i < 0 || a->len < i) return mrb_nil_value();
+ 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;
ary = mrb_ary_new_capa(mrb, len);
-
+ ptr = ARY_PTR(a);
for (j = i, k = 0; k < len; ++j, ++k) {
- mrb_ary_push(mrb, ary, a->ptr[j]);
+ mrb_ary_push(mrb, ary, ptr[j]);
}
- ptr = a->ptr + i;
- for (j = i; j < a->len - len; ++j) {
+ ptr += i;
+ for (j = i; j < alen - len; ++j) {
*ptr = *(ptr+len);
++ptr;
}
- mrb_ary_resize(mrb, self, a->len - len);
+ mrb_ary_resize(mrb, self, alen - len);
return ary;
}
diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c
index f81d38fe6..b865244cc 100644
--- a/mrbgems/mruby-random/src/random.c
+++ b/mrbgems/mruby-random/src/random.c
@@ -217,13 +217,15 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
for (i = RARRAY_LEN(ary) - 1; i > 0; i--) {
mrb_int j;
+ mrb_value *ptr = RARRAY_PTR(ary);
mrb_value tmp;
+
j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary))));
- tmp = RARRAY_PTR(ary)[i];
- mrb_ary_ptr(ary)->ptr[i] = RARRAY_PTR(ary)[j];
- mrb_ary_ptr(ary)->ptr[j] = tmp;
+ tmp = ptr[i];
+ ptr[i] = ptr[j];
+ ptr[j] = tmp;
}
}
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index deab69fd9..67762a948 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -13,8 +13,8 @@
#include <mruby/hash.h>
#include <mruby/range.h>
-#define RSTRUCT_LEN(st) mrb_ary_ptr(st)->len
-#define RSTRUCT_PTR(st) mrb_ary_ptr(st)->ptr
+#define RSTRUCT_LEN(st) RARRAY_LEN(st)
+#define RSTRUCT_PTR(st) RARRAY_PTR(st)
static struct RClass *
struct_class(mrb_state *mrb)
diff --git a/src/array.c b/src/array.c
index 7c07295c7..9124ff950 100644
--- a/src/array.c
+++ b/src/array.c
@@ -28,9 +28,15 @@ ary_new_capa(mrb_state *mrb, mrb_int capa)
blen = capa * sizeof(mrb_value);
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_FLAG(a);
+ /* 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;
}
@@ -77,8 +83,8 @@ 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;
+ array_copy(ARY_PTR(a), vals, size);
+ ARY_SET_LEN(a, size);
return mrb_obj_value(a);
}
@@ -89,9 +95,9 @@ mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
struct RArray *a;
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);
}
@@ -119,25 +125,25 @@ ary_modify(mrb_state *mrb, struct RArray *a)
ary_modify_check(mrb, a);
if (ARY_SHARED_P(a)) {
- mrb_shared_array *shared = a->aux.shared;
+ mrb_shared_array *shared = a->as.heap.aux.shared;
- if (shared->refcnt == 1 && a->ptr == shared->ptr) {
- a->ptr = shared->ptr;
- a->aux.capa = a->len;
+ 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);
}
else {
mrb_value *ptr, *p;
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);
}
ARY_UNSET_SHARED_FLAG(a);
@@ -154,18 +160,20 @@ mrb_ary_modify(mrb_state *mrb, struct RArray* a)
static void
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->ptr = ptr;
}
- shared->len = a->len;
- a->aux.shared = shared;
+ shared->len = len;
+ a->as.heap.aux.shared = shared;
ARY_SET_SHARED_FLAG(a);
}
}
@@ -173,14 +181,14 @@ ary_make_shared(mrb_state *mrb, struct RArray *a)
static void
ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
{
- mrb_int capa = a->aux.capa;
+ 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;
}
while (capa < len) {
@@ -195,21 +203,36 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
goto size_error;
}
- if (capa > a->aux.capa) {
- mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
+ 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->aux.capa = capa;
- a->ptr = expanded_ptr;
+ a->as.heap.aux.capa = capa;
+ a->as.heap.ptr = expanded_ptr;
}
}
static void
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 {
capa /= 2;
@@ -217,11 +240,11 @@ ary_shrink_capa(mrb_state *mrb, struct RArray *a)
capa = ARY_DEFAULT_LEN;
break;
}
- } while (capa > a->len * ARY_SHRINK_RATIO);
+ } while (capa > a->as.heap.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);
+ 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);
}
}
@@ -234,13 +257,13 @@ mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
ary_modify(mrb, a);
old_len = RARRAY_LEN(ary);
if (old_len != new_len) {
- a->len = new_len;
+ ARY_SET_LEN(a, new_len);
if (new_len < old_len) {
ary_shrink_capa(mrb, a);
}
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);
}
}
@@ -268,18 +291,18 @@ ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
{
mrb_int len;
- if (a2->len > ARY_MAX_SIZE - a->len) {
+ 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);
}
MRB_API void
@@ -306,16 +329,17 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
struct RArray *a1 = mrb_ary_ptr(self);
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);
}
@@ -324,11 +348,11 @@ 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)
+ if (ARY_CAPA(a) < len)
ary_expand_capa(mrb, a, len);
- array_copy(a->ptr, argv, len);
+ array_copy(ARY_PTR(a), argv, len);
mrb_write_barrier(mrb, (struct RBasic*)a);
- a->len = len;
+ ARY_SET_LEN(a, len);
}
MRB_API void
@@ -338,7 +362,7 @@ mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
struct RArray *a2 = mrb_ary_ptr(other);
if (a1 != a2) {
- ary_replace(mrb, a1, a2->ptr, a2->len);
+ ary_replace(mrb, a1, ARY_PTR(a2), ARY_LEN(a2));
}
}
@@ -359,22 +383,23 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2;
mrb_value *ptr;
- mrb_int times;
+ mrb_int times, len1;
mrb_get_args(mrb, "i", &times);
if (times < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
}
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;
}
return mrb_obj_value(a2);
@@ -384,13 +409,14 @@ static mrb_value
mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
- if (a->len > 1) {
+ 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) {
mrb_value tmp = *p1;
@@ -404,18 +430,19 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_ary_reverse(mrb_state *mrb, mrb_value self)
{
- struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len);
+ struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, ARY_LEN(a));
+ mrb_int len = ARY_LEN(a);
- if (a->len > 0) {
+ 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);
}
@@ -424,11 +451,13 @@ MRB_API void
mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
{
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);
}
@@ -450,10 +479,12 @@ MRB_API mrb_value
mrb_ary_pop(mrb_state *mrb, mrb_value ary)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int len = ARY_LEN(a);
ary_modify_check(mrb, a);
- if (a->len == 0) return mrb_nil_value();
- return a->ptr[--a->len];
+ if (len == 0) return mrb_nil_value();
+ ARY_SET_LEN(a, len-1);
+ return ARY_PTR(a)[len-1];
}
#define ARY_SHIFT_SHARED_MIN 10
@@ -462,31 +493,32 @@ MRB_API mrb_value
mrb_ary_shift(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
+ mrb_int len = ARY_LEN(a);
mrb_value val;
ary_modify_check(mrb, a);
- if (a->len == 0) return mrb_nil_value();
+ 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;
while (--size) {
*ptr = *(ptr+1);
++ptr;
}
- --a->len;
+ ARY_SET_LEN(a, len-1);
}
return val;
}
@@ -499,21 +531,25 @@ MRB_API mrb_value
mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
{
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;
+ 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;
}
- a->len++;
+ ARY_SET_LEN(a, len+1);
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, item);
return self;
@@ -523,28 +559,31 @@ static mrb_value
mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_value *vals;
- mrb_int len;
+ mrb_value *vals, *ptr;
+ mrb_int alen, len;
- mrb_get_args(mrb, "*!", &vals, &len);
- if (len > ARY_MAX_SIZE - a->len) {
+ mrb_get_args(mrb, "*!", &vals, &alen);
+ 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->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->ptr -= len;
+ a->as.heap.ptr -= len;
+ ptr = a->as.heap.ptr;
}
else {
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;
+ if (alen == 0) return self;
+ if (ARY_CAPA(a) < len + alen)
+ ary_expand_capa(mrb, a, len + alen);
+ ptr = ARY_PTR(a);
+ value_move(ptr + alen, ptr, len);
+ }
+ array_copy(ptr, vals, alen);
+ ARY_SET_LEN(a, len+alen);
while (len--) {
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[len]);
}
@@ -556,44 +595,47 @@ MRB_API mrb_value
mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
{
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();
+ if (n < 0) n += len;
+ if (n < 0 || len <= n) return mrb_nil_value();
- return a->ptr[n];
+ return ARY_PTR(a)[n];
}
MRB_API void
mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
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));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len));
}
}
- if (a->len <= n) {
- if (a->aux.capa <= n)
+ 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;
+ ary_fill_with_nil(ARY_PTR(a) + len, n + 1 - len);
+ ARY_SET_LEN(a, n+1);
}
- a->ptr[n] = val;
+ ARY_PTR(a)[n] = val;
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
}
static struct RArray*
ary_dup(mrb_state *mrb, struct RArray *a)
{
- struct RArray *d = ary_new_capa(mrb, a->len);
+ mrb_int len = ARY_LEN(a);
+ struct RArray *d = ary_new_capa(mrb, len);
- ary_replace(mrb, d, a->ptr, a->len);
+ ary_replace(mrb, d, ARY_PTR(a), len);
return d;
}
@@ -601,6 +643,7 @@ MRB_API mrb_value
mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
{
struct RArray *a = mrb_ary_ptr(ary);
+ mrb_int alen = ARY_LEN(a);
const mrb_value *argv;
mrb_int argc;
mrb_int tail;
@@ -612,66 +655,67 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
/* range check */
if (head < 0) {
- head += a->len;
+ head += alen;
if (head < 0) {
mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
}
}
tail = head + len;
- if (a->len < len || a->len < tail) {
- len = a->len - head;
+ if (alen < len || alen < tail) {
+ len = alen - head;
}
/* size check */
if (mrb_array_p(rpl)) {
argc = RARRAY_LEN(rpl);
argv = RARRAY_PTR(rpl);
- if (argv == a->ptr) {
+ if (argv == ARY_PTR(a)) {
struct RArray *r;
if (argc > 32767) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "too big recursive splice");
}
r = ary_dup(mrb, a);
- argv = r->ptr;
+ argv = ARY_PTR(r);
}
}
else {
argc = 1;
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));
}
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);
+ array_copy(ARY_PTR(a) + head, argv, argc);
}
- a->len = len;
+ ARY_SET_LEN(a, len);
}
else {
- mrb_int alen;
+ mrb_int newlen;
- 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));
+ if (alen - len > ARY_MAX_SIZE - argc) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len));
}
- alen = a->len + argc - len;
- if (alen > a->aux.capa) {
- ary_expand_capa(mrb, a, alen);
+ 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);
}
}
mrb_write_barrier(mrb, (struct RBasic*)a);
@@ -693,12 +737,15 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
{
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);
return mrb_obj_value(b);
@@ -753,14 +800,14 @@ static mrb_value
mrb_ary_aget(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int i, len;
+ mrb_int i, len, alen = ARY_LEN(a);
mrb_value index;
if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
switch (mrb_type(index)) {
/* 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, alen, TRUE) == 1) {
return ary_subseq(mrb, a, i, len);
}
else {
@@ -774,11 +821,11 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self)
}
i = aget_index(mrb, index);
- if (i < 0) i += a->len;
- if (i < 0 || a->len < i) return mrb_nil_value();
+ 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);
}
@@ -853,22 +900,23 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
mrb_int index;
mrb_value val;
mrb_value *ptr;
- mrb_int len;
+ mrb_int len, alen = ARY_LEN(a);
mrb_get_args(mrb, "i", &index);
- if (index < 0) index += a->len;
- if (index < 0 || a->len <= index) return mrb_nil_value();
+ if (index < 0) index += alen;
+ if (index < 0 || alen <= index) return mrb_nil_value();
ary_modify(mrb, a);
- val = a->ptr[index];
+ ptr = ARY_PTR(a);
+ val = ptr[index];
- ptr = a->ptr + index;
- len = a->len - 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);
@@ -879,39 +927,39 @@ static mrb_value
mrb_ary_first(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int size;
+ mrb_int size, alen = ARY_LEN(a);
if (mrb_get_args(mrb, "|i", &size) == 0) {
- return (a->len > 0)? a->ptr[0]: mrb_nil_value();
+ return (alen > 0)? ARY_PTR(a)[0]: 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)) {
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));
}
static mrb_value
mrb_ary_last(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- mrb_int size;
+ mrb_int size, alen = ARY_LEN(a);
if (mrb_get_args(mrb, "|i", &size) == 0)
- return (a->len > 0)? a->ptr[a->len - 1]: mrb_nil_value();
+ 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 ary_subseq(mrb, a, alen - size, size);
}
- return mrb_ary_new_from_values(mrb, size, a->ptr + a->len - size);
+ return mrb_ary_new_from_values(mrb, size, ARY_PTR(a) + alen - size);
}
static mrb_value
@@ -984,7 +1032,7 @@ mrb_ary_size(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- return mrb_fixnum_value(a->len);
+ return mrb_fixnum_value(ARY_LEN(a));
}
MRB_API mrb_value
@@ -994,15 +1042,14 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
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);
+ else if (!ARY_EMBED_P(a)){
+ mrb_free(mrb, a->as.heap.ptr);
}
- a->len = 0;
- a->aux.capa = 0;
- a->ptr = 0;
+ ARY_SET_EMBED_FLAG(a);
+ ARY_SET_EMBED_LEN(a, 0);
return self;
}
@@ -1012,7 +1059,7 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- return mrb_bool_value(a->len == 0);
+ return mrb_bool_value(ARY_LEN(a) == 0);
}
MRB_API mrb_value
diff --git a/src/class.c b/src/class.c
index 41a0fbad8..56f64fd4e 100644
--- a/src/class.c
+++ b/src/class.c
@@ -564,7 +564,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
va_list ap;
int argc = mrb->c->ci->argc;
int arg_i = 0;
- mrb_bool array_argv;
+ mrb_value *array_argv;
mrb_bool opt = FALSE;
mrb_bool given = TRUE;
@@ -572,15 +572,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (argc < 0) {
struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
- argc = a->len;
- array_argv = TRUE;
+ argc = ARY_LEN(a);
+ array_argv = ARY_PTR(a);
}
else {
- array_argv = FALSE;
+ array_argv = NULL;
}
#define ARGV \
- (array_argv ? mrb_ary_ptr(mrb->c->stack[1])->ptr : (mrb->c->stack + 1))
+ (array_argv ? array_argv : (mrb->c->stack + 1))
while ((c = *format++)) {
switch (c) {
@@ -751,8 +751,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
aa = to_ary(mrb, ARGV[arg_i++]);
a = mrb_ary_ptr(aa);
- *pb = a->ptr;
- *pl = a->len;
+ *pb = ARY_PTR(a);
+ *pl = ARY_LEN(a);
i++;
}
}
@@ -896,7 +896,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
{
mrb_value **var;
mrb_int *pl;
- mrb_bool nocopy = FALSE;
+ mrb_bool nocopy = array_argv ? TRUE : FALSE;
if (*format == '!') {
format++;
@@ -913,7 +913,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
else {
mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i);
RARRAY(args)->c = NULL;
- *var = (mrb_value*)RARRAY_PTR(args);
+ *var = RARRAY_PTR(args);
}
}
i = argc;
diff --git a/src/gc.c b/src/gc.c
index cad2a0a53..8cc8feb08 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -466,10 +466,13 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
}
a = mrb_ary_ptr(table);
mrb_ary_modify(mrb, a);
- for (i = 0; i < a->len; i++) {
- if (mrb_obj_eq(mrb, a->ptr[i], obj)) {
- a->len--;
- memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i]));
+ for (i = 0; i < ARY_LEN(a); i++) {
+ if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) {
+ mrb_int len = ARY_LEN(a)-1;
+ mrb_value *ptr = ARY_PTR(a);
+
+ ARY_SET_LEN(a, len);
+ memmove(&ptr[i], &ptr[i + 1], (len - i) * sizeof(mrb_value));
break;
}
}
@@ -678,8 +681,8 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
struct RArray *a = (struct RArray*)obj;
size_t i, e;
- for (i=0,e=a->len; i<e; i++) {
- mrb_gc_mark_value(mrb, a->ptr[i]);
+ for (i=0,e=ARY_LEN(a); i<e; i++) {
+ mrb_gc_mark_value(mrb, ARY_PTR(a)[i]);
}
}
break;
@@ -790,9 +793,9 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
case MRB_TT_ARRAY:
if (ARY_SHARED_P(obj))
- mrb_ary_decref(mrb, ((struct RArray*)obj)->aux.shared);
- else
- mrb_free(mrb, ((struct RArray*)obj)->ptr);
+ mrb_ary_decref(mrb, ((struct RArray*)obj)->as.heap.aux.shared);
+ else if (!ARY_EMBED_P(obj))
+ mrb_free(mrb, ((struct RArray*)obj)->as.heap.ptr);
break;
case MRB_TT_HASH:
@@ -950,7 +953,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
case MRB_TT_ARRAY:
{
struct RArray *a = (struct RArray*)obj;
- children += a->len;
+ children += ARY_LEN(a);
}
break;
diff --git a/src/hash.c b/src/hash.c
index c292f6b67..27d25b384 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -759,7 +759,7 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash)
ary = mrb_ary_new_capa(mrb, kh_size(h));
end = kh_size(h)-1;
mrb_ary_set(mrb, ary, end, mrb_nil_value());
- p = mrb_ary_ptr(ary)->ptr;
+ p = RARRAY_PTR(ary);
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
mrb_value kv = kh_key(h, k);
diff --git a/src/vm.c b/src/vm.c
index 3f3ca414f..45f9bf967 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1717,21 +1717,21 @@ RETRY_TRY_BLOCK:
if (mrb_array_p(stack[m1])) {
struct RArray *ary = mrb_ary_ptr(stack[m1]);
- pp = ary->ptr;
- len = ary->len;
+ pp = ARY_PTR(ary);
+ len = ARY_LEN(ary);
}
regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
rest = mrb_ary_ptr(regs[a]);
if (m1 > 0) {
- stack_copy(rest->ptr, stack, m1);
+ stack_copy(ARY_PTR(rest), stack, m1);
}
if (len > 0) {
- stack_copy(rest->ptr+m1, pp, len);
+ stack_copy(ARY_PTR(rest)+m1, pp, len);
}
if (m2 > 0) {
- stack_copy(rest->ptr+m1+len, stack+m1+1, m2);
+ stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2);
}
- rest->len = m1+len+m2;
+ ARY_SET_LEN(rest, m1+len+m2);
}
regs[a+1] = stack[m1+r+m2];
mrb_gc_arena_restore(mrb, ai);
@@ -1759,8 +1759,8 @@ RETRY_TRY_BLOCK:
if (argc < 0) {
struct RArray *ary = mrb_ary_ptr(regs[1]);
- argv = ary->ptr;
- argc = ary->len;
+ argv = ARY_PTR(ary);
+ argc = ARY_LEN(ary);
mrb_gc_protect(mrb, regs[1]);
}
if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
@@ -1773,8 +1773,8 @@ RETRY_TRY_BLOCK:
}
else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
mrb_gc_protect(mrb, argv[0]);
- argc = mrb_ary_ptr(argv[0])->len;
- argv = mrb_ary_ptr(argv[0])->ptr;
+ argc = RARRAY_LEN(argv[0]);
+ argv = RARRAY_PTR(argv[0]);
}
if (argc < len) {
int mlen = m2;
@@ -2645,19 +2645,19 @@ RETRY_TRY_BLOCK:
v = mrb_ary_new_from_values(mrb, 1, &regs[a]);
}
ary = mrb_ary_ptr(v);
- len = ary->len;
+ len = ARY_LEN(ary);
if (len > pre + post) {
- v = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
+ v = mrb_ary_new_from_values(mrb, len - pre - post, ARY_PTR(ary)+pre);
regs[a++] = v;
while (post--) {
- regs[a++] = ary->ptr[len-post-1];
+ regs[a++] = ARY_PTR(ary)[len-post-1];
}
}
else {
v = mrb_ary_new_capa(mrb, 0);
regs[a++] = v;
for (idx=0; idx+pre<len; idx++) {
- regs[a+idx] = ary->ptr[pre+idx];
+ regs[a+idx] = ARY_PTR(ary)[pre+idx];
}
while (idx < post) {
SET_NIL_VALUE(regs[a+idx]);