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.
This commit is contained in:
Yukihiro "Matz" Matsumoto
2017-07-27 12:46:51 +09:00
parent 5d44f8582e
commit f26d00d9e8
9 changed files with 303 additions and 225 deletions
+33 -7
View File
@@ -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)
+11 -11
View File
@@ -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;
}
+5 -3
View File
@@ -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;
}
}
+2 -2
View File
@@ -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)
+215 -168
View File
@@ -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);
a->aux.capa = capa;
a->ptr = expanded_ptr;
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;
}
}
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);
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(a->ptr, vals, len);
a->len += 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
+9 -9
View File
@@ -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;
+13 -10
View File
@@ -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;
+1 -1
View File
@@ -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);
+14 -14
View File
@@ -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]);