summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gdbinit29
-rw-r--r--ChangeLog17
-rw-r--r--array.c417
-rw-r--r--ext/tk/tcltklib.c9
-rw-r--r--gc.c2
-rw-r--r--include/ruby/ruby.h33
-rw-r--r--parse.y2
-rw-r--r--proc.c6
8 files changed, 363 insertions, 152 deletions
diff --git a/.gdbinit b/.gdbinit
index 8598cf0ab7..96e033fa88 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -104,9 +104,34 @@ define rp
print (struct RRegexp *)$arg0
else
if ($flags & RUBY_T_MASK) == RUBY_T_ARRAY
- printf "T_ARRAY: len=%ld ", ((struct RArray*)$arg0)->len
+ if ($flags & RUBY_FL_USER1)
+ set $len = (($flags & (RUBY_FL_USER3|RUBY_FL_USER4)) >> (RUBY_FL_USHIFT+3))
+ printf "T_ARRAY: len=%ld ", $len
+ printf "(embed) "
+ if ($len == 0)
+ printf "{(empty)} "
+ else
+ output/x *((VALUE*)((struct RArray*)$arg0)->as.ary) @ $len
+ printf " "
+ end
+ else
+ set $len = ((struct RArray*)$arg0)->as.heap.len
+ printf "T_ARRAY: len=%ld ", $len
+ if ($flags & RUBY_FL_USER2)
+ printf "(shared) shared="
+ output/x ((struct RArray*)$arg0)->as.heap.aux.shared
+ printf " "
+ else
+ printf "(ownership) capa=%ld ", ((struct RArray*)$arg0)->as.heap.aux.capa
+ end
+ if ($len == 0)
+ printf "{(empty)} "
+ else
+ output/x *((VALUE*)((struct RArray*)$arg0)->as.heap.ptr) @ $len
+ printf " "
+ end
+ end
print (struct RArray *)$arg0
- x/xw ((struct RArray*)$arg0)->ptr
else
if ($flags & RUBY_T_MASK) == RUBY_T_FIXNUM
printf "T_FIXNUM: "
diff --git a/ChangeLog b/ChangeLog
index 59eafc6ce8..20a220ddc9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Thu Oct 9 14:37:59 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
+
+ * include/ruby/ruby.h: embeds the elements of an array into its
+ struct RArray for # of elements <= 3.
+
+ * array.c: ditto.
+
+ * gc.c (gc_mark_children): following the change of struct RArray.
+
+ * ext/tk/tcltklib.c (ip_ruby_cmp): ditto.
+
+ * parse.y (coverage): ditto.
+
+ * proc.c (curry): ditto.
+
+ * .gdbinit: ditto.
+
Thu Oct 9 11:29:33 2008 NARUSE, Yui <naruse@ruby-lang.org>
* encoding.c (Init_Encoding): new instance method Encoding#names,
diff --git a/array.c b/array.c
index e33c7bc0b1..4aa6dbef07 100644
--- a/array.c
+++ b/array.c
@@ -14,6 +14,7 @@
#include "ruby/ruby.h"
#include "ruby/util.h"
#include "ruby/st.h"
+#include <assert.h>
VALUE rb_cArray;
@@ -38,18 +39,120 @@ memfill(register VALUE *mem, register long size, register VALUE val)
}
}
-#define ARY_SHARED_P(a) FL_TEST(a, ELTS_SHARED)
+# define ARY_SHARED_P(ary) \
+ (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \
+ FL_TEST(ary,ELTS_SHARED))
+# define ARY_EMBED_P(ary) \
+ (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \
+ FL_TEST(ary, RARRAY_EMBED_FLAG))
+#define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
+#define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
+#define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
+#define ARY_EMBED_LEN(a) \
+ (assert(ARY_EMBED_P(a)), \
+ (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
+ (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
+
+#define ARY_OWNS_HEAP_P(a) (!FL_TEST(a, ELTS_SHARED|RARRAY_EMBED_FLAG))
+#define FL_SET_EMBED(a) do { \
+ assert(!ARY_SHARED_P(a)); \
+ assert(!OBJ_FROZEN(a)); \
+ FL_SET(a, RARRAY_EMBED_FLAG); \
+} while (0)
+#define FL_UNSET_EMBED(ary) FL_UNSET(ary, RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
+#define FL_SET_SHARED(ary) do { \
+ assert(!ARY_EMBED_P(ary)); \
+ FL_SET(ary, ELTS_SHARED); \
+} while (0)
+#define FL_UNSET_SHARED(ary) FL_UNSET(ary, ELTS_SHARED)
+
+#define ARY_SET_PTR(ary, p) do { \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
+ RARRAY(ary)->as.heap.ptr = (p); \
+} while (0)
+#define ARY_SET_EMBED_LEN(ary, n) do { \
+ long tmp_n = n; \
+ assert(ARY_EMBED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
+ RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
+ RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
+} while (0)
+#define ARY_SET_HEAP_LEN(ary, n) do { \
+ assert(!ARY_EMBED_P(ary)); \
+ RARRAY(ary)->as.heap.len = n; \
+} while (0)
#define ARY_SET_LEN(ary, n) do { \
- RARRAY(ary)->len = (n);\
+ if (ARY_EMBED_P(ary)) { \
+ ARY_SET_EMBED_LEN(ary, n); \
+ } \
+ else { \
+ ARY_SET_HEAP_LEN(ary, n); \
+ } \
+ assert(RARRAY_LEN(ary) == n); \
} while (0)
+#define ARY_INCREASE_PTR(ary, n) do { \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
+ RARRAY(ary)->as.heap.ptr += n; \
+} while (0)
+#define ARY_INCREASE_LEN(ary, n) do { \
+ assert(!OBJ_FROZEN(ary)); \
+ if (ARY_EMBED_P(ary)) { \
+ ARY_SET_EMBED_LEN(ary, RARRAY_LEN(ary)+n); \
+ } \
+ else { \
+ RARRAY(ary)->as.heap.len += n; \
+ } \
+} while (0)
+
+#define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : RARRAY(ary)->as.heap.aux.capa)
+#define ARY_SET_CAPA(ary, n) do { \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!ARY_SHARED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
+ RARRAY(ary)->as.heap.aux.capa = (n); \
+} while (0)
-#define ARY_CAPA(ary) RARRAY(ary)->aux.capa
-#define RESIZE_CAPA(ary,capacity) do {\
- REALLOC_N(RARRAY(ary)->ptr, VALUE, (capacity));\
- RARRAY(ary)->aux.capa = (capacity);\
+#define ARY_SHARED(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared)
+#define ARY_SET_SHARED(ary, value) do { \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(ARY_SHARED_P(ary)); \
+ RARRAY(ary)->as.heap.aux.shared = (value); \
} while (0)
+static void
+RESIZE_CAPA(VALUE ary, long capacity)
+{
+ assert(!OBJ_FROZEN(ary));
+ assert(!ARY_SHARED_P(ary));
+ if (capacity > RARRAY_EMBED_LEN_MAX) {
+ if (ARY_EMBED_P(ary)) {
+ long len = ARY_EMBED_LEN(ary);
+ VALUE *ptr = ALLOC_N(VALUE, (capacity));
+ MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
+ FL_UNSET_EMBED(ary);
+ ARY_SET_PTR(ary, ptr);
+ ARY_SET_HEAP_LEN(ary, len);
+ }
+ else {
+ REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, (capacity));
+ }
+ ARY_SET_CAPA(ary, (capacity));
+ }
+ else {
+ if (!ARY_EMBED_P(ary)) {
+ long len = RARRAY_LEN(ary);
+ VALUE *ptr = RARRAY_PTR(ary);
+ MEMCPY(RARRAY(ary)->as.ary, ptr, VALUE, len);
+ FL_SET_EMBED(ary);
+ ARY_SET_LEN(ary, len);
+ xfree(ptr);
+ }
+ }
+}
+
static inline void
rb_ary_modify_check(VALUE ary)
{
@@ -61,15 +164,23 @@ rb_ary_modify_check(VALUE ary)
static void
rb_ary_modify(VALUE ary)
{
- VALUE *ptr;
-
rb_ary_modify_check(ary);
if (ARY_SHARED_P(ary)) {
- ptr = ALLOC_N(VALUE, RARRAY_LEN(ary));
- FL_UNSET(ary, ELTS_SHARED);
- RARRAY(ary)->aux.capa = RARRAY_LEN(ary);
- MEMCPY(ptr, RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
- RARRAY(ary)->ptr = ptr;
+ long len = RARRAY_LEN(ary);
+ if (len <= RARRAY_EMBED_LEN_MAX) {
+ VALUE *ptr = ARY_HEAP_PTR(ary);
+ FL_UNSET_SHARED(ary);
+ FL_SET_EMBED(ary);
+ MEMCPY(ARY_EMBED_PTR(ary), ptr, VALUE, len);
+ ARY_SET_EMBED_LEN(ary, len);
+ }
+ else {
+ VALUE *ptr = ALLOC_N(VALUE, len);
+ FL_UNSET_SHARED(ary);
+ ARY_SET_CAPA(ary, len);
+ MEMCPY(ptr, RARRAY_PTR(ary), VALUE, len);
+ ARY_SET_PTR(ary, ptr);
+ }
}
}
@@ -99,10 +210,8 @@ ary_alloc(VALUE klass)
{
NEWOBJ(ary, struct RArray);
OBJSETUP(ary, klass, T_ARRAY);
-
- ary->len = 0;
- ary->ptr = 0;
- ary->aux.capa = 0;
+ FL_SET_EMBED((VALUE)ary);
+ ARY_SET_EMBED_LEN((VALUE)ary, 0);
return (VALUE)ary;
}
@@ -119,9 +228,12 @@ ary_new(VALUE klass, long len)
rb_raise(rb_eArgError, "array size too big");
}
ary = ary_alloc(klass);
- if (len == 0) len++;
- RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
- RARRAY(ary)->aux.capa = len;
+ if (len > RARRAY_EMBED_LEN_MAX) {
+ FL_UNSET_EMBED(ary);
+ ARY_SET_PTR(ary, ALLOC_N(VALUE, len));
+ ARY_SET_CAPA(ary, len);
+ ARY_SET_HEAP_LEN(ary, 0);
+ }
return ary;
}
@@ -136,7 +248,7 @@ rb_ary_new2(long len)
VALUE
rb_ary_new(void)
{
- return rb_ary_new2(ARY_DEFAULT_SIZE);
+ return rb_ary_new2(RARRAY_EMBED_LEN_MAX);
}
#include <stdarg.h>
@@ -156,7 +268,7 @@ rb_ary_new3(long n, ...)
}
va_end(ar);
- RARRAY(ary)->len = n;
+ ARY_SET_LEN(ary, n);
return ary;
}
@@ -168,7 +280,7 @@ rb_ary_new4(long n, const VALUE *elts)
ary = rb_ary_new2(n);
if (n > 0 && elts) {
MEMCPY(RARRAY_PTR(ary), elts, VALUE, n);
- RARRAY(ary)->len = n;
+ ARY_SET_LEN(ary, n);
}
return ary;
@@ -183,31 +295,48 @@ rb_ary_tmp_new(long len)
void
rb_ary_free(VALUE ary)
{
- if (!ARY_SHARED_P(ary)) {
- xfree(RARRAY(ary)->ptr);
+ if (ARY_OWNS_HEAP_P(ary)) {
+ xfree(RARRAY_PTR(ary));
}
}
static VALUE
ary_make_shared(VALUE ary)
{
+ assert(!ARY_EMBED_P(ary));
if (ARY_SHARED_P(ary)) {
- return RARRAY(ary)->aux.shared;
+ return ARY_SHARED(ary);
}
else {
NEWOBJ(shared, struct RArray);
OBJSETUP(shared, 0, T_ARRAY);
+ FL_UNSET_EMBED(shared);
- shared->len = RARRAY(ary)->len;
- shared->ptr = RARRAY(ary)->ptr;
- shared->aux.capa = RARRAY(ary)->aux.capa;
- RARRAY(ary)->aux.shared = (VALUE)shared;
- FL_SET(ary, ELTS_SHARED);
+ ARY_SET_LEN((VALUE)shared, RARRAY_LEN(ary));
+ ARY_SET_PTR((VALUE)shared, RARRAY_PTR(ary));
+ ARY_SET_CAPA((VALUE)shared, ARY_CAPA(ary));
+ FL_SET_SHARED(ary);
+ ARY_SET_SHARED(ary, (VALUE)shared);
OBJ_FREEZE(shared);
return (VALUE)shared;
}
}
+
+static VALUE
+ary_make_substitution(VALUE ary)
+{
+ if (RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX) {
+ VALUE subst = rb_ary_new2(RARRAY_LEN(ary));
+ MEMCPY(ARY_EMBED_PTR(subst), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
+ ARY_SET_EMBED_LEN(subst, RARRAY_LEN(ary));
+ return subst;
+ }
+ else {
+ return ary_make_shared(ary);
+ }
+}
+
VALUE
rb_assoc_new(VALUE car, VALUE cdr)
{
@@ -298,10 +427,12 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
rb_ary_modify(ary);
if (argc == 0) {
- if (RARRAY_PTR(ary) && !ARY_SHARED_P(ary)) {
- xfree(RARRAY(ary)->ptr);
+ if (ARY_OWNS_HEAP_P(ary) && RARRAY_PTR(ary)) {
+ xfree(RARRAY_PTR(ary));
}
- RARRAY(ary)->len = 0;
+ FL_UNSET_SHARED(ary);
+ FL_SET_EMBED(ary);
+ ARY_SET_EMBED_LEN(ary, 0);
if (rb_block_given_p()) {
rb_warning("given block not used");
}
@@ -333,12 +464,12 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
}
for (i=0; i<len; i++) {
rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
- RARRAY(ary)->len = i + 1;
+ ARY_SET_LEN(ary, i + 1);
}
}
else {
memfill(RARRAY_PTR(ary), len, val);
- RARRAY(ary)->len = len;
+ ARY_SET_LEN(ary, len);
}
return ary;
}
@@ -355,15 +486,11 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
static VALUE
rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
{
- VALUE ary = ary_alloc(klass);
-
- if (argc < 0) {
- rb_raise(rb_eArgError, "negative array size");
+ VALUE ary = ary_new(klass, argc);
+ if (argc > 0 && argv) {
+ MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
+ ARY_SET_LEN(ary, argc);
}
- RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
- RARRAY(ary)->aux.capa = argc;
- MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
- RARRAY(ary)->len = argc;
return ary;
}
@@ -401,28 +528,41 @@ rb_ary_store(VALUE ary, long idx, VALUE val)
}
if (idx >= RARRAY_LEN(ary)) {
- RARRAY(ary)->len = idx + 1;
+ ARY_SET_LEN(ary, idx + 1);
}
RARRAY_PTR(ary)[idx] = val;
}
static VALUE
-ary_shared_array(VALUE klass, VALUE ary)
+ary_make_partial0(VALUE ary, long offset, long len)
{
- VALUE val = ary_alloc(klass);
+ assert(offset >= 0);
+ assert(len >= 0);
+ assert(offset+len <= RARRAY_LEN(ary));
- ary_make_shared(ary);
- RARRAY(val)->ptr = RARRAY(ary)->ptr;
- RARRAY(val)->len = RARRAY(ary)->len;
- RARRAY(val)->aux.shared = RARRAY(ary)->aux.shared;
- FL_SET(val, ELTS_SHARED);
- return val;
+ if (len <= RARRAY_EMBED_LEN_MAX) {
+ return rb_ary_new4(len, RARRAY_PTR(ary) + offset);
+ }
+ else {
+ VALUE shared, result = ary_alloc(rb_obj_class(ary));
+ FL_UNSET_EMBED(result);
+
+ shared = ary_make_shared(ary);
+ ARY_SET_PTR(result, RARRAY_PTR(ary));
+ ARY_SET_LEN(result, RARRAY_LEN(ary));
+ FL_SET_SHARED(result);
+ ARY_SET_SHARED(result, shared);
+
+ ARY_INCREASE_PTR(result, offset);
+ ARY_SET_LEN(result, len);
+ return result;
+ }
}
static VALUE
-ary_shared_first(int argc, VALUE *argv, VALUE ary, int last)
+ary_make_partial(int argc, VALUE *argv, VALUE ary, int last)
{
- VALUE nv, result;
+ VALUE nv;
long n;
long offset = 0;
@@ -437,11 +577,7 @@ ary_shared_first(int argc, VALUE *argv, VALUE ary, int last)
if (last) {
offset = RARRAY_LEN(ary) - n;
}
- result = ary_shared_array(rb_cArray, ary);
- RARRAY(result)->ptr += offset;
- RARRAY(result)->len = n;
-
- return result;
+ return ary_make_partial0(ary, offset, n);
}
/*
@@ -492,14 +628,14 @@ rb_ary_pop(VALUE ary)
long n;
rb_ary_modify_check(ary);
if (RARRAY_LEN(ary) == 0) return Qnil;
- if (!ARY_SHARED_P(ary) &&
+ if (ARY_OWNS_HEAP_P(ary) &&
RARRAY_LEN(ary) * 3 < ARY_CAPA(ary) &&
ARY_CAPA(ary) > ARY_DEFAULT_SIZE)
{
RESIZE_CAPA(ary, RARRAY_LEN(ary) * 2);
}
n = RARRAY_LEN(ary)-1;
- RARRAY(ary)->len = n;
+ ARY_SET_LEN(ary, n);
return RARRAY_PTR(ary)[n];
}
@@ -530,8 +666,8 @@ rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
}
rb_ary_modify_check(ary);
- result = ary_shared_first(argc, argv, ary, Qtrue);
- RARRAY(ary)->len -= RARRAY_LEN(result);
+ result = ary_make_partial(argc, argv, ary, Qtrue);
+ ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
return result;
}
@@ -546,14 +682,16 @@ rb_ary_shift(VALUE ary)
if (!ARY_SHARED_P(ary)) {
if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1);
- RARRAY(ary)->len--;
+ ARY_INCREASE_LEN(ary, -1);
return top;
}
+ assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */
+
RARRAY_PTR(ary)[0] = Qnil;
ary_make_shared(ary);
}
- RARRAY(ary)->ptr++; /* shift ptr */
- RARRAY(ary)->len--;
+ ARY_INCREASE_PTR(ary, 1); /* shift ptr */
+ ARY_INCREASE_LEN(ary, -1);
return top;
}
@@ -590,16 +728,15 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
}
rb_ary_modify_check(ary);
- result = ary_shared_first(argc, argv, ary, Qfalse);
+ result = ary_make_partial(argc, argv, ary, Qfalse);
n = RARRAY_LEN(result);
if (ARY_SHARED_P(ary)) {
- RARRAY(ary)->ptr += n;
- RARRAY(ary)->len -= n;
- }
+ ARY_INCREASE_PTR(ary, n);
+ }
else {
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
- RARRAY(ary)->len -= n;
}
+ ARY_INCREASE_LEN(ary, -n);
return result;
}
@@ -623,14 +760,14 @@ rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
if (argc == 0) return ary;
rb_ary_modify(ary);
- if (RARRAY(ary)->aux.capa <= (len = RARRAY(ary)->len) + argc) {
+ if (ARY_CAPA(ary) <= (len = RARRAY_LEN(ary)) + argc) {
RESIZE_CAPA(ary, len + argc + ARY_DEFAULT_SIZE);
}
/* sliding items */
- MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
- MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
- RARRAY(ary)->len += argc;
+ MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len);
+ MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
+ ARY_INCREASE_LEN(ary, argc);
return ary;
}
@@ -664,8 +801,7 @@ rb_ary_entry(VALUE ary, long offset)
VALUE
rb_ary_subseq(VALUE ary, long beg, long len)
{
- VALUE klass, ary2, shared;
- VALUE *ptr;
+ VALUE klass;
if (beg > RARRAY_LEN(ary)) return Qnil;
if (beg < 0 || len < 0) return Qnil;
@@ -676,15 +812,7 @@ rb_ary_subseq(VALUE ary, long beg, long len)
klass = rb_obj_class(ary);
if (len == 0) return ary_new(klass, 0);
- shared = ary_make_shared(ary);
- ptr = RARRAY_PTR(ary);
- ary2 = ary_alloc(klass);
- RARRAY(ary2)->ptr = ptr + beg;
- RARRAY(ary2)->len = len;
- RARRAY(ary2)->aux.shared = shared;
- FL_SET(ary2, ELTS_SHARED);
-
- return ary2;
+ return ary_make_partial0(ary, beg, len);
}
/*
@@ -794,7 +922,7 @@ rb_ary_first(int argc, VALUE *argv, VALUE ary)
return RARRAY_PTR(ary)[0];
}
else {
- return ary_shared_first(argc, argv, ary, Qfalse);
+ return ary_make_partial(argc, argv, ary, Qfalse);
}
}
@@ -819,7 +947,7 @@ rb_ary_last(int argc, VALUE *argv, VALUE ary)
return RARRAY_PTR(ary)[RARRAY_LEN(ary)-1];
}
else {
- return ary_shared_first(argc, argv, ary, Qtrue);
+ return ary_make_partial(argc, argv, ary, Qtrue);
}
}
@@ -1003,7 +1131,7 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
if (rlen > 0) {
MEMCPY(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
}
- RARRAY(ary)->len = len;
+ ARY_SET_LEN(ary, len);
}
else {
long alen;
@@ -1020,7 +1148,7 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
if (len != rlen) {
MEMMOVE(RARRAY_PTR(ary) + beg + rlen, RARRAY_PTR(ary) + beg + len,
VALUE, RARRAY_LEN(ary) - (beg + len));
- RARRAY(ary)->len = alen;
+ ARY_SET_LEN(ary, alen);
}
if (rlen > 0) {
MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
@@ -1238,10 +1366,11 @@ VALUE
rb_ary_dup(VALUE ary)
{
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
-
+ int is_embed = ARY_EMBED_P(dup);
DUPSETUP(dup, ary);
+ if (is_embed) FL_SET_EMBED(dup);
MEMCPY(RARRAY_PTR(dup), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
- RARRAY(dup)->len = RARRAY_LEN(ary);
+ ARY_SET_LEN(dup, RARRAY_LEN(ary));
return dup;
}
@@ -1548,8 +1677,9 @@ VALUE
rb_ary_sort_bang(VALUE ary)
{
rb_ary_modify(ary);
+ assert(!ARY_SHARED_P(ary));
if (RARRAY_LEN(ary) > 1) {
- VALUE tmp = ary_make_shared(ary);
+ VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
struct ary_sort_data data;
RBASIC(tmp)->klass = 0;
@@ -1558,18 +1688,39 @@ rb_ary_sort_bang(VALUE ary)
data.opt_inited = 0;
ruby_qsort(RARRAY_PTR(tmp), RARRAY_LEN(tmp), sizeof(VALUE),
rb_block_given_p()?sort_1:sort_2, &data);
- if (RARRAY(ary)->ptr != RARRAY(tmp)->ptr) {
- if (!ARY_SHARED_P(ary)) xfree(RARRAY(ary)->ptr);
- RARRAY(ary)->ptr = RARRAY(tmp)->ptr;
- RARRAY(ary)->len = RARRAY(tmp)->len;
- RARRAY(ary)->aux.capa = RARRAY(tmp)->aux.capa;
- FL_SET(ary, ELTS_SHARED);
- };
- FL_UNSET(ary, ELTS_SHARED);
- RARRAY(tmp)->ptr = 0;
- RARRAY(tmp)->len = 0;
- RARRAY(tmp)->aux.capa = 0;
- RBASIC(tmp)->klass = rb_cArray;
+
+ if (ARY_EMBED_P(ary) || ARY_EMBED_P(tmp)) {
+ assert(ARY_EMBED_P(tmp));
+ MEMCPY(RARRAY_PTR(ary), ARY_EMBED_PTR(tmp), VALUE, ARY_EMBED_LEN(tmp));
+ ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
+ }
+ else {
+ assert(!ARY_EMBED_P(ary));
+ assert(!ARY_EMBED_P(tmp));
+ if (RARRAY_PTR(ary) != RARRAY_PTR(tmp)) {
+ assert(!ARY_SHARED_P(tmp));
+ if (ARY_SHARED_P(ary)) {
+ FL_UNSET_SHARED(ary);
+ }
+ else {
+ xfree(ARY_HEAP_PTR(ary));
+ }
+ ARY_SET_PTR(ary, RARRAY_PTR(tmp));
+ ARY_SET_HEAP_LEN(ary, RARRAY_LEN(tmp));
+ ARY_SET_CAPA(ary, ARY_CAPA(tmp));
+ }
+ else {
+ FL_UNSET_SHARED(ary);
+ ARY_SET_CAPA(ary, ARY_CAPA(tmp));
+ }
+ /* tmp was lost ownership for the ptr */
+ FL_UNSET(tmp, FL_FREEZE);
+ FL_SET_EMBED(tmp);
+ ARY_SET_EMBED_LEN(tmp, 0);
+ FL_SET(tmp, FL_FREEZE);
+ }
+ /* tmp will be GC'ed. */
+ RBASIC(tmp)->klass = rb_cArray;
}
return ary;
}
@@ -1778,7 +1929,7 @@ rb_ary_delete(VALUE ary, VALUE item)
rb_ary_modify(ary);
if (RARRAY_LEN(ary) > i2) {
- RARRAY(ary)->len = i2;
+ ARY_SET_LEN(ary, i2);
if (i2 * 2 < ARY_CAPA(ary) &&
ARY_CAPA(ary) > ARY_DEFAULT_SIZE) {
RESIZE_CAPA(ary, i2*2);
@@ -1804,7 +1955,7 @@ rb_ary_delete_at(VALUE ary, long pos)
del = RARRAY_PTR(ary)[pos];
MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE,
RARRAY_LEN(ary)-pos-1);
- RARRAY(ary)->len--;
+ ARY_INCREASE_LEN(ary, -1);
return del;
}
@@ -1921,7 +2072,7 @@ rb_ary_reject_bang(VALUE ary)
if (RARRAY_LEN(ary) == i2) return Qnil;
if (i2 < RARRAY_LEN(ary))
- RARRAY(ary)->len = i2;
+ ARY_SET_LEN(ary, i2);
return ary;
}
@@ -2089,22 +2240,30 @@ rb_ary_transpose(VALUE ary)
VALUE
rb_ary_replace(VALUE copy, VALUE orig)
{
- VALUE shared;
- VALUE *ptr;
-
orig = to_ary(orig);
rb_ary_modify_check(copy);
if (copy == orig) return copy;
- shared = ary_make_shared(orig);
- if (!ARY_SHARED_P(copy)) {
- ptr = RARRAY(copy)->ptr;
- xfree(ptr);
- }
- RARRAY(copy)->ptr = RARRAY(orig)->ptr;
- RARRAY(copy)->len = RARRAY(orig)->len;
- RARRAY(copy)->aux.shared = shared;
- FL_SET(copy, ELTS_SHARED);
+ if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) {
+ VALUE *ptr;
+ if (ARY_OWNS_HEAP_P(copy)) xfree(RARRAY_PTR(copy));
+ FL_UNSET_SHARED(copy);
+ FL_SET_EMBED(copy);
+ ptr = RARRAY_PTR(orig);
+ MEMCPY(RARRAY_PTR(copy), ptr, VALUE, RARRAY_LEN(orig));
+ ARY_SET_LEN(copy, RARRAY_LEN(orig));
+ }
+ else {
+ VALUE shared = ary_make_shared(orig);
+ if (ARY_OWNS_HEAP_P(copy)) {
+ xfree(RARRAY_PTR(copy));
+ }
+ FL_UNSET_EMBED(copy);
+ FL_SET_SHARED(copy);
+ ARY_SET_PTR(copy, RARRAY_PTR(orig));
+ ARY_SET_LEN(copy, RARRAY_LEN(orig));
+ ARY_SET_SHARED(copy, shared);
+ }
return copy;
}
@@ -2122,7 +2281,7 @@ VALUE
rb_ary_clear(VALUE ary)
{
rb_ary_modify(ary);
- RARRAY(ary)->len = 0;
+ ARY_SET_LEN(ary, 0);
if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
RESIZE_CAPA(ary, ARY_DEFAULT_SIZE * 2);
}
@@ -2201,7 +2360,7 @@ rb_ary_fill(int argc, VALUE *argv, VALUE ary)
RESIZE_CAPA(ary, end);
}
rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), end - RARRAY_LEN(ary));
- RARRAY(ary)->len = end;
+ ARY_SET_LEN(ary, end);
}
if (block_p) {
@@ -2245,7 +2404,7 @@ rb_ary_plus(VALUE x, VALUE y)
z = rb_ary_new2(len);
MEMCPY(RARRAY_PTR(z), RARRAY_PTR(x), VALUE, RARRAY_LEN(x));
MEMCPY(RARRAY_PTR(z) + RARRAY_LEN(x), RARRAY_PTR(y), VALUE, RARRAY_LEN(y));
- RARRAY(z)->len = len;
+ ARY_SET_LEN(z, len);
return z;
}
@@ -2307,7 +2466,7 @@ rb_ary_times(VALUE ary, VALUE times)
len *= RARRAY_LEN(ary);
ary2 = ary_new(rb_obj_class(ary), len);
- RARRAY(ary2)->len = len;
+ ARY_SET_LEN(ary2, len);
for (i=0; i<len; i+=RARRAY_LEN(ary)) {
MEMCPY(RARRAY_PTR(ary2)+i, RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
@@ -2716,7 +2875,7 @@ rb_ary_uniq_bang(VALUE ary)
rb_ary_store(ary, j++, v);
}
}
- RARRAY(ary)->len = j;
+ ARY_SET_LEN(ary, j);
return ary;
}
@@ -2771,7 +2930,7 @@ rb_ary_compact_bang(VALUE ary)
if (n * 2 < ARY_CAPA(ary) && ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
RESIZE_CAPA(ary, n * 2);
}
- RARRAY(ary)->len = n;
+ ARY_SET_LEN(ary, n);
return ary;
}
@@ -3168,7 +3327,7 @@ permute0(long n, long r, long *p, long index, int *used, VALUE values)
const VALUE *values_array = RARRAY_PTR(values);
for (j = 0; j < r; j++) result_array[j] = values_array[p[j]];
- RARRAY(result)->len = r;
+ ARY_SET_LEN(result, r);
rb_yield(result);
}
}
@@ -3228,7 +3387,7 @@ rb_ary_permutation(int argc, VALUE *argv, VALUE ary)
long *p = (long*)RSTRING_PTR(t0);
volatile VALUE t1 = tmpbuf(n,sizeof(int));
int *used = (int*)RSTRING_PTR(t1);
- VALUE ary0 = ary_make_shared(ary); /* private defensive copy of ary */
+ VALUE ary0 = ary_make_substitution(ary); /* private defensive copy of ary */
for (i = 0; i < n; i++) used[i] = 0; /* initialize array */
diff --git a/ext/tk/tcltklib.c b/ext/tk/tcltklib.c
index 1946272340..a8829d3b69 100644
--- a/ext/tk/tcltklib.c
+++ b/ext/tk/tcltklib.c
@@ -3089,9 +3089,6 @@ ip_ruby_cmd(clientData, interp, argc, argv)
/* get args */
args = rb_ary_new2(argc - 2);
-#ifdef HAVE_STRUCT_RARRAY_LEN
- RARRAY(args)->len = 0;
-#endif
for(i = 3; i < argc; i++) {
#if TCL_MAJOR_VERSION >= 8
str = Tcl_GetStringFromObj(argv[i], &len);
@@ -3099,14 +3096,14 @@ ip_ruby_cmd(clientData, interp, argc, argv)
#ifndef HAVE_STRUCT_RARRAY_LEN
rb_ary_push(args, rb_tainted_str_new(str, len));
#else
- RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new(str, len);
+ RARRAY(args)->as.heap.ptr[RARRAY(args)->as.heap.len++] = rb_tainted_str_new(str, len);
#endif
#else /* TCL_MAJOR_VERSION < 8 */
DUMP2("arg:%s",argv[i]);
#ifndef HAVE_STRUCT_RARRAY_LEN
rb_ary_push(args, rb_tainted_str_new2(argv[i]));
#else
- RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new2(argv[i]);
+ RARRAY(args)->as.heap.ptr[RARRAY(args)->as.heap.len++] = rb_tainted_str_new2(argv[i]);
#endif
#endif
}
@@ -8298,7 +8295,7 @@ ip_invoke_with_position(argc, argv, obj, position)
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
- ret = RARRAY(result)->ptr[0];
+ ret = RARRAY(result)->as.heap.ptr[0];
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */
#else
diff --git a/gc.c b/gc.c
index c467cb1d62..47e58b7198 100644
--- a/gc.c
+++ b/gc.c
@@ -1462,7 +1462,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
case T_ARRAY:
if (FL_TEST(obj, ELTS_SHARED)) {
- ptr = obj->as.array.aux.shared;
+ ptr = obj->as.array.as.heap.aux.shared;
goto again;
}
else {
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 1c53777fc9..243390b1f0 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -504,7 +504,7 @@ VALUE rb_newobj(void);
if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\
} while (0)
#define DUPSETUP(dup,obj) do {\
- OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED));\
+ OBJSETUP(dup,rb_obj_class(obj), (RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED)); \
if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\
} while (0)
@@ -596,17 +596,34 @@ struct RString {
RSTRING(str)->as.heap.ptr)
#define RSTRING_END(str) (RSTRING_PTR(str)+RSTRING_LEN(str))
+#define RARRAY_EMBED_LEN_MAX 3
struct RArray {
struct RBasic basic;
- long len;
union {
- long capa;
- VALUE shared;
- } aux;
- VALUE *ptr;
+ struct {
+ long len;
+ union {
+ long capa;
+ VALUE shared;
+ } aux;
+ VALUE *ptr;
+ } heap;
+ VALUE ary[RARRAY_EMBED_LEN_MAX];
+ } as;
};
-#define RARRAY_LEN(a) RARRAY(a)->len
-#define RARRAY_PTR(a) RARRAY(a)->ptr
+#define RARRAY_EMBED_FLAG FL_USER1
+/* FL_USER2 is for ELTS_SHARED */
+#define RARRAY_EMBED_LEN_MASK (FL_USER4|FL_USER3)
+#define RARRAY_EMBED_LEN_SHIFT (FL_USHIFT+3)
+#define RARRAY_LEN(a) \
+ ((RBASIC(a)->flags & RARRAY_EMBED_FLAG) ? \
+ (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
+ (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)) : \
+ RARRAY(a)->as.heap.len)
+#define RARRAY_PTR(a) \
+ ((RBASIC(a)->flags & RARRAY_EMBED_FLAG) ? \
+ RARRAY(a)->as.ary : \
+ RARRAY(a)->as.heap.ptr)
struct RRegexp {
struct RBasic basic;
diff --git a/parse.y b/parse.y
index 6b2914208a..b40a430c65 100644
--- a/parse.y
+++ b/parse.y
@@ -4945,7 +4945,7 @@ coverage(const char *f, int n)
int i;
RBASIC(lines)->klass = 0;
for (i = 0; i < n; i++) RARRAY_PTR(lines)[i] = Qnil;
- RARRAY(lines)->len = n;
+ RARRAY(lines)->as.heap.len = n;
rb_hash_aset(coverages, fname, lines);
return lines;
}
diff --git a/proc.c b/proc.c
index 705a7640b2..4907d80bbb 100644
--- a/proc.c
+++ b/proc.c
@@ -1674,11 +1674,7 @@ static VALUE curry(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_
static VALUE
make_curry_proc(VALUE proc, VALUE passed, VALUE arity)
{
- VALUE args = rb_ary_new2(3);
- RARRAY_PTR(args)[0] = proc;
- RARRAY_PTR(args)[1] = passed;
- RARRAY_PTR(args)[2] = arity;
- RARRAY_LEN(args) = 3;
+ VALUE args = rb_ary_new3(3, proc, passed, arity);
rb_ary_freeze(passed);
rb_ary_freeze(args);
return rb_proc_new(curry, args);