[#5737] returning strings from methods/instance_methods — TRANS <transfire@...>

I was just wondering why with #methods and #instance_methods, it was

11 messages 2005/09/08

[#5796] proposed attr writer patch — Daniel Berger <Daniel.Berger@...>

Hi all,

18 messages 2005/09/16

[#5798] Makefile error in OpenSLL extension (on Windows) — noreply@...

Bugs item #2472, was opened at 2005-09-16 18:56

11 messages 2005/09/17
[#5800] Re: [ ruby-Bugs-2472 ] Makefile error in OpenSLL extension (on Windows) — nobu.nokada@... 2005/09/17

Hi,

[#5851] Re: RubyGems in Ruby HEAD — Paul van Tilburg <paul@...>

Hi all,

34 messages 2005/09/21
[#5867] Re: RubyGems in Ruby HEAD — mathew <meta@...> 2005/09/21

Paul van Tilburg wrote:

[#5870] Re: RubyGems in Ruby HEAD — Marc Dequènes (Duck) <Duck@...> 2005/09/21

[#5920] Re: RubyGems in Ruby HEAD — mathew <meta@...> 2005/09/22

Marc Dequ竪nes (Duck) wrote:

[#5926] Re: RubyGems in Ruby HEAD — Pascal Terjan <pterjan@...> 2005/09/23

On 9/22/05, mathew <meta@pobox.com> wrote:

[#5931] Re: RubyGems in Ruby HEAD — Austin Ziegler <halostatue@...> 2005/09/23

On 9/23/05, Pascal Terjan <pterjan@gmail.com> wrote:

[#5898] Delegate and Forwardable Documentation — James Edward Gray II <james@...>

I've tried to send these files through a couple of times now with

17 messages 2005/09/22
[#5911] Re: Delegate and Forwardable Documentation — James Edward Gray II <james@...> 2005/09/22

On Sep 22, 2005, at 9:02 AM, James Edward Gray II wrote:

[#5924] Re: Delegate and Forwardable Documentation — James Edward Gray II <james@...> 2005/09/23

On Sep 22, 2005, at 11:53 AM, James Edward Gray II wrote:

[#5941] Re: Delegate and Forwardable Documentation — Yukihiro Matsumoto <matz@...> 2005/09/23

Hi,

[#5942] Re: Delegate and Forwardable Documentation — James Edward Gray II <james@...> 2005/09/23

On Sep 23, 2005, at 10:54 AM, Yukihiro Matsumoto wrote:

[#5947] Re: Delegate and Forwardable Documentation — Yukihiro Matsumoto <matz@...> 2005/09/23

Hi,

[#5921] Mutually dependent libs double loading. — TRANS <transfire@...>

I'm on Ruby 1.8.2.

14 messages 2005/09/23
[#5923] Re: Mutually dependent libs double loading. — Florian Gro<florgro@...> 2005/09/23

TRANS wrote:

[#5985] Finally an answer to my RubyGems question and some small suggestions — TRANS <transfire@...>

I appreciate those that attempted to offer me some info on this issue.

9 messages 2005/09/26

[#6001] Require Namepaces and RubyGems' effect on LoadPath problem — TRANS <transfire@...>

I've added namespaces to require. Works like this:

94 messages 2005/09/26
[#6002] Re: Require Namepaces and RubyGems' effect on LoadPath problem — Austin Ziegler <halostatue@...> 2005/09/26

On 9/26/05, TRANS <transfire@gmail.com> wrote:

[#6003] Re: Require Namepaces and RubyGems' effect on LoadPath problem — TRANS <transfire@...> 2005/09/26

On 9/26/05, Austin Ziegler <halostatue@gmail.com> wrote:

[#6005] Re: Require Namepaces and RubyGems' effect on LoadPath problem — Austin Ziegler <halostatue@...> 2005/09/26

On 9/26/05, TRANS <transfire@gmail.com> wrote:

[#6007] gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Sam Roberts <sroberts@...> 2005/09/26

Quoting halostatue@gmail.com, on Tue, Sep 27, 2005 at 06:02:07AM +0900:

[#6013] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Austin Ziegler <halostatue@...> 2005/09/27

On 9/26/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6014] Re: gems is a language change, not a pkging system — Sam Roberts <sroberts@...> 2005/09/27

Quoting halostatue@gmail.com, on Tue, Sep 27, 2005 at 10:29:17AM +0900:

[#6015] Re: gems is a language change, not a pkging system — James Edward Gray II <james@...> 2005/09/27

On Sep 26, 2005, at 8:54 PM, Sam Roberts wrote:

[#6016] Re: gems is a language change, not a pkging system — Sam Roberts <sroberts@...> 2005/09/27

Quoting james@grayproductions.net, on Tue, Sep 27, 2005 at 11:06:01AM +0900:

[#6018] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/26/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6019] Re: gems is a language change, not a pkging system — Sam Roberts <sroberts@...> 2005/09/27

Quoting halostatue@gmail.com, on Tue, Sep 27, 2005 at 11:49:14AM +0900:

[#6024] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/27/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6025] Re: gems is a language change, not a pkging system — Ralph Amissah <ralph.amissah@...> 2005/09/27

> Right now, they're watching people who have pretty much sat on the side

[#6026] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/27/05, Ralph Amissah <ralph.amissah@gmail.com> wrote:

[#6043] Re: gems is a language change, not a pkging system — Ralph Amissah <ralph.amissah@...> 2005/09/28

I'll greatly weaken my post, and give everyone the opportunity to head me

[#6044] Re: gems is a language change, not a pkging system — Hugh Sasse <hgs@...> 2005/09/28

On Wed, 28 Sep 2005, Ralph Amissah wrote:

[#6073] Re: gems is a language change, not a pkging system — Mauricio Fern疣dez <mfp@...> 2005/09/28

Hello,

[#6074] Re: gems is a language change, not a pkging system — Jim Weirich <jim@...> 2005/09/29

On Wednesday 28 September 2005 07:35 pm, Mauricio Fern疣dez wrote:

[#6017] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/26/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6046] Re: gems is a language change, not a pkging system — "Sean E. Russell" <ser@...> 2005/09/28

On Monday 26 September 2005 22:41, Austin Ziegler wrote:

[#6050] Re: gems is a language change, not a pkging system — Hugh Sasse <hgs@...> 2005/09/28

On Wed, 28 Sep 2005, Sean E. Russell wrote:

[#6207] Re: gems is a language change, not a pkging system — "Sean E. Russell" <ser@...> 2005/10/10

On Wednesday 28 September 2005 08:54, Hugh Sasse wrote:

[#6045] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — "Sean E. Russell" <ser@...> 2005/09/28

On Monday 26 September 2005 21:29, Austin Ziegler wrote:

[#6048] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Austin Ziegler <halostatue@...> 2005/09/28

On 9/28/05, Sean E. Russell <ser@germane-software.com> wrote:

[#6059] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Dominique Brezinski <dominique.brezinski@...> 2005/09/28

On 9/28/05, Austin Ziegler <halostatue@gmail.com> wrote:

[#6061] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Austin Ziegler <halostatue@...> 2005/09/28

On 9/28/05, Dominique Brezinski <dominique.brezinski@gmail.com> wrote:

[#6062] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Dominique Brezinski <dominique.brezinski@...> 2005/09/28

For what it is worth, I live life behind an authenticated proxy, so I

[#6099] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — "Sean E. Russell" <ser@...> 2005/09/30

On Wednesday 28 September 2005 08:43, Austin Ziegler wrote:

[#6009] Re: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — Ralph Amissah <ralph.amissah@...>

(i) correction, segfault is with official ruby 1.8.3 (2005-09-21), not

21 messages 2005/09/27
[#6010] Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — Ralph Amissah <ralph.amissah@...> 2005/09/27

[sorry for duplicate post]

[#6079] Re: Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — ts <decoux@...> 2005/09/29

>>>>> "R" == Ralph Amissah <ralph.amissah@gmail.com> writes:

[#6081] Re: Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — ts <decoux@...> 2005/09/29

>>>>> "t" == ts <decoux@moulon.inra.fr> writes:

[#6082] Re: Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — Tanaka Akira <akr@...17n.org> 2005/09/29

In article <200509291419.j8TEJYid015419@moulon.inra.fr>,

another array patch - performance boosts all over the place

From: Eric Mahurin <eric_mahurin@...>
Date: 2005-09-21 16:56:21 UTC
List: ruby-core #5861
Is anybody interested in the patches I'm doing to make arrays
(and someday strings) faster?  I didn't see a response for my
last patch (shift/unshift).  Now I have another patch
(fastarray.diff - attached) that should help out a lot more
code sequences.  Here are the results using the attached
benchmark (end_test.rb):

n = 32768 (2**15)

code                        old   new
------------------------- ----- -----
;                          0.01  0.01
shift                      0.02  0.02
shift(1)                   0.03  0.04
pop                        0.02  0.01
pop(1)                     0.04  0.05
shift;pop                  0.02  0.02
shift(1);pop(1)            0.07  0.08
unshift(i)                 2.34  0.02
push(i)                    0.02  0.02
unshift(i);push(i)         2.35  0.03
unshift(shift)            17.61  0.03
unshift(*shift(1))        17.42  0.07
push(pop)                  0.04  0.02
push(*pop(1))             13.83  0.08
push(shift)               14.64  0.03
push(*shift(1))           15.39  0.08
unshift(pop)               2.33  0.03
unshift(*pop(1))          16.47  0.08
slice!(1)                  2.29  0.03
delete_at(1)               2.30  0.02
slice!(1,1)               12.75  0.05
self[1,1]=[]               2.36  0.05
slice!(-2)                 0.02  0.03
delete_at(-2)              0.02  0.02
slice!(-2,1)              10.37  0.05
self[-2,1]=[]              0.04  0.04
self[1,0]=[i]              3.49  0.04
insert(1,i)                3.44  0.04
self[-1,0]=[i]             1.07  0.05
insert(-2,i)               1.02  0.05
self[1,0]=slice!(1,1)     16.40  0.06
insert(1,delete_at(1))     5.60  0.06
self[-1,0]=slice!(-2,1)   11.92  0.06
insert(-2,delete_at(-2))   1.00  0.06
self[-1,0]=slice!(1,1)    14.10  0.07
insert(-2,delete_at(1))    3.29  0.06
self[1,0]=slice!(-2,1)    14.06  0.07
insert(1,delete_at(-2))    3.30  0.06
self[i]=self[i]            0.03  0.02
self[i]=at(i)              0.03  0.02
self[i,1]=self[i,1]       11.72  0.06
self[-i-1]=self[-i-1]      0.05  0.05
self[-i-1]=at(-i-1)        0.04  0.05
self[-i-1,1]=self[-i-1,1] 11.74  0.07
self[-i-1]=self[i]         0.03  0.03
self[-i-1]=at(i)           0.03  0.04
self[-i-1,1]=self[i,1]    11.67  0.07
self[i]=self[-i-1]         0.04  0.04
self[i]=at(-i-1)           0.03  0.03
self[i,1]=self[-i-1,1]    11.70  0.06

In each of the tests above, it runs the code n times on an
array that has an average length of n.  The massive performance
boosts you see above is because the old (current) code was O(n)
in those cases and my patched code is O(1).

Here were the changes I made:

- added a bit (ELTS_LFREE=FL_USER3) to say whether there is
free space to the left of ary->ptr and put the number of free
elements in ary->ptr[-1].

- instead of ary->aux.capa, did the same for free space to the
right of ary->ptr+ary->len-1 (new flag: ELTS_RFREE=FL_USER3 and
amount stored in ary->ptr[ary->len]).  This freed up
ary->shared for dedicated used (instead of being a union with
capa).

- instead of shared arrays all pointing to a common frozen
array object, put shared arrays in a circular linked list (used
ary->shared).  The original master array will have
ELTS_SHARED=0 and the others will have ELTS_SHARED=1.  Unshared
arrays will have ELTS_SHARED=0 and ary->shared=0.

- when a shared array is to be modified, there are 2 cases:
slave - make copy and remove from shared circular linked list;
master - make copies of all slaves and terminate sharing
between this master and its slaves.  When a shared array is to
be freed, it operates in a similar way.

- during GC, shared arrays are treated independently (master
can be freed).  This works because of the above mechanism. 
Before, unused object references would persist because of array
sharing (keeping an array slice around would keep references to
all objects in the original array).

- modified various functions (shift, unshift, delete_at,
splice), to insert/delete toward the closest side to minimize
the number of elements needed to be moved.

Does anybody see a downside to this?  The main problem I see is
that I don't see the big picture when making these changes
(i.e. GC).  And this needs to be better tested.  Anybody know
of something good to do array testing?  I just used the
self-testing benchmark attached and what's in test/ruby.

Eric



		
__________________________________ 
Yahoo! Mail - PC Magazine Editors' Choice 2005 
http://mail.yahoo.com

Attachments (2)

fastarray.diff (25.3 KB, text/x-diff)
Index: array.c
===================================================================
RCS file: /src/ruby/array.c,v
retrieving revision 1.179
diff -u -r1.179 array.c
--- array.c	12 Sep 2005 15:23:54 -0000	1.179
+++ array.c	21 Sep 2005 16:13:02 -0000
@@ -16,6 +16,7 @@
 #include "util.h"
 #include "st.h"
 #include "node.h"
+#include "rubysig.h"
 
 VALUE rb_cArray, rb_cValues;
 
@@ -52,20 +53,63 @@
 }
 
 static void
-rb_ary_modify(VALUE ary)
+rb_ary_unshare(VALUE ary, int freeit)
 {
+    VALUE shared = RARRAY(ary)->shared;
+    VALUE next = shared;
+    VALUE cur;
     VALUE *ptr;
-
-    rb_ary_modify_check(ary);
+    VALUE *freeptr = 0;
     if (FL_TEST(ary, ELTS_SHARED)) {
-	ptr = ALLOC_N(VALUE, RARRAY(ary)->len);
+        if (freeit) {
+            RARRAY(ary)->ptr = 0;
+        } else {
+            ptr = ALLOC_N(VALUE, RARRAY(ary)->len);
+            MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
+            RARRAY(ary)->ptr = ptr;
+        }
 	FL_UNSET(ary, ELTS_SHARED);
-	RARRAY(ary)->aux.capa = RARRAY(ary)->len;
-	MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
-	RARRAY(ary)->ptr = ptr;
+        RARRAY(ary)->shared = 0;
+        do {
+            cur = next;
+            next = RARRAY(cur)->shared;
+        } while (next!=ary);
+        if (cur==shared) {
+            RARRAY(cur)->shared = 0;
+        } else {
+            RARRAY(cur)->shared = shared;
+        }
+    } else if (RARRAY(ary)->ptr) {
+        if (freeit) {
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            freeptr = RARRAY(ary)->ptr-lfree;
+            FL_UNSET(ary, ELTS_LFREE);
+            FL_UNSET(ary, ELTS_RFREE);
+            RARRAY(ary)->ptr = 0;
+        }
+        if (shared) for (;;) {
+            RARRAY(ary)->shared = 0;
+            ary = shared;
+            shared = RARRAY(ary)->shared;
+            if (!shared) break;
+            ptr = ALLOC_N(VALUE, RARRAY(ary)->len);
+	    MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
+	    FL_UNSET(ary, ELTS_SHARED);
+	    RARRAY(ary)->ptr = ptr;
+        }
+        if (freeptr) RUBY_CRITICAL(free(freeptr));
     }
 }
 
+static void
+rb_ary_modify(VALUE ary)
+{
+    VALUE *ptr;
+
+    rb_ary_modify_check(ary);
+    rb_ary_unshare(ary,0);
+}
+
 VALUE
 rb_ary_freeze(VALUE ary)
 {
@@ -96,7 +140,7 @@
 
     ary->len = 0;
     ary->ptr = 0;
-    ary->aux.capa = 0;
+    ary->shared = 0;
 
     return (VALUE)ary;
 }
@@ -116,7 +160,6 @@
     
     ary = ary_alloc(klass);
     RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
-    RARRAY(ary)->aux.capa = len;
 
     return ary;
 }
@@ -146,7 +189,7 @@
     ary = rb_ary_new2(n);
 
     va_start(ar, n);
-    for (i=0; i<n; i++) {
+    for (i=0; i<n; i++) {               
 	RARRAY(ary)->ptr[i] = va_arg(ar, VALUE);
     }
     va_end(ar);
@@ -196,44 +239,62 @@
     if (n > 0 && elts) {
 	RARRAY(val)->len = n;
 	MEMCPY(RARRAY(val)->ptr, elts, VALUE, n);
+    } else if (n > 0) {
+        RARRAY(val)->ptr[0] = n;
+        FL_SET(val,ELTS_RFREE);
     }
 
     return val;
 }
 
 static VALUE
-ary_make_shared(VALUE ary)
+ary_share(VALUE val, VALUE ary)
 {
+    /*
     if (!FL_TEST(ary, ELTS_SHARED)) {
 	NEWOBJ(shared, struct RArray);
 	OBJSETUP(shared, rb_cArray, T_ARRAY);
 
 	shared->len = RARRAY(ary)->len;
 	shared->ptr = RARRAY(ary)->ptr;
-	shared->aux.capa = RARRAY(ary)->aux.capa;
-	RARRAY(ary)->aux.shared = (VALUE)shared;
+        if (FL_TEST(ary,ELTS_RFREE)) {
+            FL_SET(shared,ELTS_RFREE);
+            FL_UNSET(ary,ELTS_RFREE);
+        }
+        if (FL_TEST(ary,ELTS_LFREE)) {
+            FL_SET(shared,ELTS_LFREE);
+            FL_UNSET(ary,ELTS_LFREE);
+        }
+	RARRAY(ary)->shared = (VALUE)shared;
 	FL_SET(ary, ELTS_SHARED);
 	OBJ_FREEZE(shared);
-	return (VALUE)shared;
     }
-    else {
-	return RARRAY(ary)->aux.shared;
+    */
+    RARRAY(val)->ptr = RARRAY(ary)->ptr;
+    RARRAY(val)->len = RARRAY(ary)->len;
+    if (RARRAY(ary)->shared) {
+        RARRAY(val)->shared = RARRAY(ary)->shared;
+    } else {
+        RARRAY(val)->shared = ary;
     }
+    RARRAY(ary)->shared = val;
+    FL_SET(val, ELTS_SHARED);
+    return val;
 }
 
 static VALUE
 ary_shared_array(VALUE klass, VALUE ary)
 {
-    VALUE val = ary_alloc(klass);
+    return ary_share(ary_alloc(klass),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;
+void
+ary_free(VALUE obj)
+{
+    rb_ary_unshare(obj,1);
 }
 
+
 VALUE
 rb_values_from_ary(VALUE ary)
 {
@@ -315,8 +376,17 @@
 {
     long len;
     VALUE size, val;
+    long capa;
 
     if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
+        if (!FL_TEST(ary,ELTS_SHARED)) {
+            rb_ary_modify(ary);
+            capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
+            if (capa) {
+                FL_SET(ary,ELTS_RFREE);
+                RARRAY(ary)->ptr[0] = capa;
+            }
+        }
 	RARRAY(ary)->len = 0;
 	if (rb_block_given_p()) {
 	    rb_warning("given block not used");
@@ -340,9 +410,13 @@
 	rb_raise(rb_eArgError, "array size too big");
     }
     rb_ary_modify(ary);
-    if (len > RARRAY(ary)->aux.capa) {
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
-	RARRAY(ary)->aux.capa = len;
+    capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
+    if (len > capa) {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, len + lfree);
+        RARRAY(ary)->ptr += lfree;
+	capa = len;
     }
     if (rb_block_given_p()) {
 	long i;
@@ -359,6 +433,12 @@
 	memfill(RARRAY(ary)->ptr, len, val);
 	RARRAY(ary)->len = len;
     }
+    if (capa > len) {
+        FL_SET(ary,ELTS_RFREE);
+        RARRAY(ary)->ptr[len] = capa-len;
+    } else {
+        FL_UNSET(ary,ELTS_RFREE);
+    }
 
     return ary;
 }
@@ -381,7 +461,7 @@
 	RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
 	MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
     }
-    RARRAY(ary)->len = RARRAY(ary)->aux.capa = argc;
+    RARRAY(ary)->len = argc;
 
     return ary;
 }
@@ -389,6 +469,7 @@
 void
 rb_ary_store(VALUE ary, long idx, VALUE val)
 {
+    long capa;
     if (idx < 0) {
 	idx += RARRAY(ary)->len;
 	if (idx < 0) {
@@ -398,8 +479,10 @@
     }
 
     rb_ary_modify(ary);
-    if (idx >= RARRAY(ary)->aux.capa) {
-	long new_capa = RARRAY(ary)->aux.capa / 2;
+    capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
+    if (idx >= capa) {
+	long new_capa = capa / 2;
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
 
 	if (new_capa < ARY_DEFAULT_SIZE) {
 	    new_capa = ARY_DEFAULT_SIZE;
@@ -408,8 +491,10 @@
 	if (new_capa * (long)sizeof(VALUE) <= new_capa) {
 	    rb_raise(rb_eArgError, "index too big");
 	}
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa);
-	RARRAY(ary)->aux.capa = new_capa;
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa + lfree);
+        RARRAY(ary)->ptr += lfree;
+	capa = new_capa;
     }
     if (idx > RARRAY(ary)->len) {
 	rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len,
@@ -417,7 +502,14 @@
     }
 
     if (idx >= RARRAY(ary)->len) {
-	RARRAY(ary)->len = idx + 1;
+	long len = idx + 1;
+        RARRAY(ary)->len = len;
+        if (capa > len) {
+            FL_SET(ary,ELTS_RFREE);
+            RARRAY(ary)->ptr[len] = capa-len;
+        } else {
+            FL_UNSET(ary,ELTS_RFREE);
+        }
     }
     RARRAY(ary)->ptr[idx] = val;
 }
@@ -495,15 +587,30 @@
 VALUE
 rb_ary_pop(VALUE ary)
 {
-    rb_ary_modify_check(ary);
+    long capa;
+    VALUE item;
+    if (!FL_TEST(ary, ELTS_SHARED)) {
+        rb_ary_modify(ary);
+    } else {
+        rb_ary_modify_check(ary);
+    }
     if (RARRAY(ary)->len == 0) return Qnil;
+    capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
     if (!FL_TEST(ary, ELTS_SHARED) &&
-	    RARRAY(ary)->len * 2 < RARRAY(ary)->aux.capa &&
-	    RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
-	RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
+	    RARRAY(ary)->len * 2 < capa &&
+	    capa > ARY_DEFAULT_SIZE) {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+	capa = RARRAY(ary)->len * 2;
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, capa + lfree);
+        RARRAY(ary)->ptr += lfree;
+    }
+    item = RARRAY(ary)->ptr[--RARRAY(ary)->len];
+    if (!FL_TEST(ary, ELTS_SHARED)) {
+        RARRAY(ary)->ptr[RARRAY(ary)->len] = capa-RARRAY(ary)->len;
+        FL_SET(ary,ELTS_RFREE);
     }
-    return RARRAY(ary)->ptr[--RARRAY(ary)->len];
+    return item;
 }
 
 /*
@@ -523,15 +630,20 @@
 rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
 {
     VALUE result;
+    long n;
 
     if (argc == 0) {
 	return rb_ary_pop(ary);
     }
 
-    rb_ary_modify_check(ary);
-
     result = ary_shared_last(argc, argv, ary);
-    RARRAY(ary)->len -= RARRAY(result)->len;
+    rb_ary_modify(ary);
+    n = RARRAY(result)->len;
+    if (n) {
+        long rfree = FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0; 
+        RARRAY(ary)->ptr[RARRAY(ary)->len -= n] = rfree+n;
+        FL_SET(ary,ELTS_RFREE);
+    }
     return result;
 }
 
@@ -540,10 +652,20 @@
 {
     VALUE top;
 
-    rb_ary_modify_check(ary);
     if (RARRAY(ary)->len == 0) return Qnil;
     top = RARRAY(ary)->ptr[0];
-    ary_make_shared(ary);
+    if (!FL_TEST(ary,ELTS_SHARED)) {
+        rb_ary_modify(ary);
+        if (FL_TEST(ary,ELTS_LFREE)) {
+            RARRAY(ary)->ptr[0] = RARRAY(ary)->ptr[-1]+1;
+        } else {
+            FL_SET(ary, ELTS_LFREE);
+            RARRAY(ary)->ptr[0] = 1;
+        }
+    } else {
+        rb_ary_modify_check(ary);
+    }
+        
     RARRAY(ary)->ptr++;		/* shift ptr */
     RARRAY(ary)->len--;
 
@@ -577,36 +699,17 @@
 	return rb_ary_shift(ary);
     }
 
-    rb_ary_modify_check(ary);
-
     result = ary_shared_first(argc, argv, ary);
-    n = RARRAY(result)->len;
-    RARRAY(ary)->ptr += n;
-    RARRAY(ary)->len -= n;
-
-    return result;
-}
-
-VALUE
-rb_ary_unshift(VALUE ary, VALUE item)
-{
     rb_ary_modify(ary);
-    if (RARRAY(ary)->len == RARRAY(ary)->aux.capa) {
-	long capa_inc = RARRAY(ary)->aux.capa / 2;
-	if (capa_inc < ARY_DEFAULT_SIZE) {
-	    capa_inc = ARY_DEFAULT_SIZE;
-	}
-	RARRAY(ary)->aux.capa += capa_inc;
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
+    n = RARRAY(result)->len;
+    if (n) {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0; 
+        (RARRAY(ary)->ptr += n)[-1] = lfree+n;
+        RARRAY(ary)->len -= n;
+        FL_SET(ary,ELTS_LFREE);
     }
 
-    /* sliding items */
-    MEMMOVE(RARRAY(ary)->ptr + 1, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
-
-    RARRAY(ary)->len++;
-    RARRAY(ary)->ptr[0] = item;
-
-    return ary;
+    return result;
 }
 
 /*
@@ -624,20 +727,50 @@
 static VALUE
 rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
 {
-    long len = RARRAY(ary)->len;
-
-    if (argc == 0) return ary;
-
-    /* make rooms by setting the last item */
-    rb_ary_store(ary, len + argc - 1, Qnil);
-
-    /* sliding items */
-    MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
-    MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
+    long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
     
+    rb_ary_modify_check(ary);
+    if (lfree<argc) {
+        long len = RARRAY(ary)->len;
+        long rfree = (FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0)/2;
+	long free2 = argc+(RARRAY(ary)->len+argc)/2;
+        VALUE *ptr;
+	if (free2 < ARY_DEFAULT_SIZE) {
+	    free2 = ARY_DEFAULT_SIZE;
+	}
+        ptr = ALLOC_N(VALUE,len+free2)+(free2-rfree);
+        MEMMOVE(ptr, RARRAY(ary)->ptr, VALUE, len);
+        ary_free(ary);
+        RARRAY(ary)->ptr = ptr;
+        if (rfree) {
+            RARRAY(ary)->ptr[len] = rfree;
+            FL_SET(ary,ELTS_RFREE);
+        } else {
+            FL_UNSET(ary,ELTS_RFREE);
+        }
+        lfree = free2-rfree;
+        FL_SET(ary, ELTS_LFREE);
+    }
+
+    RARRAY(ary)->ptr -= argc;
+    RARRAY(ary)->len += argc;
+    lfree -= argc;
+    if (lfree) {
+        RARRAY(ary)->ptr[-1] = lfree;
+    } else {
+        FL_UNSET(ary, ELTS_LFREE);
+    }
+    MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
+
     return ary;
 }
 
+VALUE
+rb_ary_unshift(VALUE ary, VALUE item)
+{
+    return rb_ary_unshift_m(1,&item,ary);
+}
+
 /* faster version - use this if you don't need to treat negative offset */
 static inline VALUE
 rb_ary_elt(VALUE ary, long offset)
@@ -661,7 +794,7 @@
 static VALUE
 rb_ary_subseq(VALUE ary, long beg, long len)
 {
-    VALUE klass, ary2, shared;
+    VALUE klass, ary2;
     VALUE *ptr;
 
     if (beg > RARRAY(ary)->len) return Qnil;
@@ -675,13 +808,9 @@
     klass = rb_obj_class(ary);
     if (len == 0) return ary_new(klass, 0);
 
-    shared = ary_make_shared(ary);
-    ptr = RARRAY(ary)->ptr;
-    ary2 = ary_alloc(klass);
-    RARRAY(ary2)->ptr = ptr + beg;
+    ary2 = ary_shared_array(klass,ary);
+    RARRAY(ary2)->ptr += beg;
     RARRAY(ary2)->len = len;
-    RARRAY(ary2)->aux.shared = shared;
-    FL_SET(ary2, ELTS_SHARED);
 
     return ary2;
 }
@@ -968,6 +1097,11 @@
 rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
 {
     long rlen;
+    long alen;
+    long beg0;
+    long diff;
+    VALUE *ptr;
+    long alen0 = RARRAY(ary)->len;
 
     if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
     if (beg < 0) {
@@ -977,9 +1111,6 @@
 	    rb_raise(rb_eIndexError, "index %ld out of array", beg);
 	}
     }
-    if (beg + len > RARRAY(ary)->len) {
-	len = RARRAY(ary)->len - beg;
-    }
 
     if (rpl == Qundef) {
 	rlen = 0;
@@ -988,41 +1119,100 @@
 	rpl = rb_ary_to_ary(rpl);
 	rlen = RARRAY(rpl)->len;
     }
+
     rb_ary_modify(ary);
 
-    if (beg >= RARRAY(ary)->len) {
-	len = beg + rlen;
-	if (len >= RARRAY(ary)->aux.capa) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
-	    RARRAY(ary)->aux.capa = len;
-	}
-	rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, beg - RARRAY(ary)->len);
-	if (rlen > 0) {
-	    MEMCPY(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
-	}
-	RARRAY(ary)->len = len;
-    }
-    else {
-	long alen;
+    beg0 = beg;
+    ptr = RARRAY(ary)->ptr;
 
-	if (beg + len > RARRAY(ary)->len) {
-	    len = RARRAY(ary)->len - beg;
-	}
+    if (beg + len > RARRAY(ary)->len) {
+        len = RARRAY(ary)->len - beg;
+        if (len<0) beg0 = beg + len;
+    }
 
-	alen = RARRAY(ary)->len + rlen - len;
-	if (alen >= RARRAY(ary)->aux.capa) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, alen);
-	    RARRAY(ary)->aux.capa = alen;
-	}
+    diff = rlen - len;
+    alen = alen0 + diff;
 
-	if (len != rlen) {
-	    MEMMOVE(RARRAY(ary)->ptr + beg + rlen, RARRAY(ary)->ptr + beg + len,
-		    VALUE, RARRAY(ary)->len - (beg + len));
-	    RARRAY(ary)->len = alen;
-	}
-	if (rlen > 0) {
-	    MEMMOVE(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
-	}
+    if (diff) {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? ptr[-1] : 0;
+        long rfree = FL_TEST(ary,ELTS_RFREE) ? ptr[alen0] : 0;
+        if (beg>=alen/2) {
+            rfree -= diff;
+            if (rfree<0) {
+                long free2 = alen/2;
+                if (lfree>free2/2) {
+                    lfree = free2/2;
+                }
+                rfree = free2-lfree;
+                ptr = ALLOC_N(VALUE, alen+free2) + lfree;
+                MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, beg0);
+                MEMCPY(ptr+beg+rlen, RARRAY(ary)->ptr+beg+len, VALUE, alen0 - (beg+len));
+                if (rlen > 0) {
+                    MEMMOVE(ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
+                }
+                ary_free(ary);
+                if (lfree) {
+                    ptr[-1] = lfree;
+                    FL_SET(ary,ELTS_LFREE);
+                } else {
+                    FL_UNSET(ary,ELTS_LFREE);
+                }
+                RARRAY(ary)->ptr = ptr;
+            } else {
+                MEMMOVE(ptr+beg+rlen, ptr+beg+len, VALUE, alen0 - (beg+len));
+                if (rlen > 0) {
+                    MEMMOVE(ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
+                }
+            }
+            if (rfree) {
+                ptr[alen] = rfree;
+                FL_SET(ary, ELTS_RFREE);
+            } else {
+                FL_UNSET(ary, ELTS_RFREE);
+            }
+        } else {
+            ptr -= diff;
+            lfree -= diff;
+            if (lfree<0) {
+                long free2 = alen/2;
+                if (rfree>free2/2) {
+                    rfree = free2/2;
+                }
+                lfree = free2-rfree;
+                ptr = ALLOC_N(VALUE, alen+free2) + lfree;
+                MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, beg0);
+                MEMCPY(ptr+beg+rlen, RARRAY(ary)->ptr+beg+len,
+                    VALUE, alen0 - (beg+len));
+                if (rlen > 0) {
+                    MEMMOVE(ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
+                }
+                ary_free(ary);
+                if (rfree) {
+                    ptr[alen] = rfree;
+                    FL_SET(ary,ELTS_RFREE);
+                } else {
+                    FL_UNSET(ary,ELTS_RFREE);
+                }
+            } else {
+                MEMMOVE(ptr, ptr+diff, VALUE, beg0);
+                if (rlen > 0) {
+                    MEMMOVE(ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
+                }
+            }
+            if (lfree) {
+                ptr[-1] = lfree;
+                FL_SET(ary, ELTS_LFREE);
+            } else {
+                FL_UNSET(ary, ELTS_LFREE);
+            }
+            RARRAY(ary)->ptr = ptr;
+        }
+        RARRAY(ary)->len = alen;
+    } else if (rlen > 0) {
+        MEMMOVE(ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
+    }
+    if (len < 0) {
+        rb_mem_clear(ptr + beg0, -len);
     }
 }
 
@@ -1730,6 +1920,7 @@
 rb_ary_delete(VALUE ary, VALUE item)
 {
     long i1, i2;
+    long capa;
 
     for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) {
 	VALUE e = RARRAY(ary)->ptr[i1];
@@ -1748,13 +1939,23 @@
     }
 
     rb_ary_modify(ary);
+    capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
     if (RARRAY(ary)->len > i2) {
 	RARRAY(ary)->len = i2;
-	if (i2 * 2 < RARRAY(ary)->aux.capa &&
-	    RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, i2 * 2);
-	    RARRAY(ary)->aux.capa = i2 * 2;
-	}
+	if (i2 * 2 < capa &&
+	    capa > ARY_DEFAULT_SIZE) {
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            RARRAY(ary)->ptr -= lfree;
+	    REALLOC_N(RARRAY(ary)->ptr, VALUE, i2 * 2 + lfree);
+            RARRAY(ary)->ptr += lfree;
+	    capa = i2 * 2;
+	}
+        if (capa>i2) {
+            RARRAY(ary)->ptr[i2] = capa-i2;
+            FL_SET(ary,ELTS_RFREE);
+        } else {
+            FL_UNSET(ary,ELTS_RFREE);
+        }
     }
 
     return item;
@@ -1763,8 +1964,10 @@
 VALUE
 rb_ary_delete_at(VALUE ary, long pos)
 {
-    long i, len = RARRAY(ary)->len;
+    long len = RARRAY(ary)->len;
     VALUE del;
+    long rfree;
+    VALUE *ptr;
 
     if (pos >= len) return Qnil;
     if (pos < 0) {
@@ -1773,11 +1976,27 @@
     }
 
     rb_ary_modify(ary);
-    del = RARRAY(ary)->ptr[pos];
-    for (i = pos + 1; i < len; i++, pos++) {
-	RARRAY(ary)->ptr[pos] = RARRAY(ary)->ptr[i];
+    ptr = RARRAY(ary)->ptr;
+    del = ptr[pos];
+    if (pos>=len/2) {
+        VALUE *eptr = ptr+len;
+        long rfree = FL_TEST(ary,ELTS_RFREE) ? *eptr : 0;
+        --len;
+        --eptr;
+        ptr += pos;
+        MEMMOVE(ptr, ptr+1, VALUE, len-pos);
+        RARRAY(ary)->len = len;
+        *eptr = rfree+1;
+        FL_SET(ary,ELTS_RFREE);
+    } else {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? ptr[-1] : 0;
+        --len;
+        MEMMOVE(ptr+1, ptr, VALUE, pos);
+        *ptr = lfree+1;
+        RARRAY(ary)->len = len;
+        RARRAY(ary)->ptr = ptr+1;
+        FL_SET(ary,ELTS_LFREE);
     }
-    RARRAY(ary)->len = pos;
 
     return del;
 }
@@ -1866,9 +2085,11 @@
 rb_ary_reject_bang(VALUE ary)
 {
     long i1, i2;
+    long rfree;
 
     RETURN_ENUMERATOR(ary, 0, 0);
     rb_ary_modify(ary);
+    rfree = FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0;
     for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) {
 	VALUE v = RARRAY(ary)->ptr[i1];
 	if (RTEST(rb_yield(v))) continue;
@@ -1878,8 +2099,12 @@
 	i2++;
     }
     if (RARRAY(ary)->len == i2) return Qnil;
-    if (i2 < RARRAY(ary)->len)
+    if (i2 < RARRAY(ary)->len) {
+        rfree += RARRAY(ary)->len-i2;
+        RARRAY(ary)->ptr[i2] = rfree;
+        FL_SET(ary,ELTS_RFREE);
 	RARRAY(ary)->len = i2;
+    }
 
     return ary;
 }
@@ -2031,18 +2256,11 @@
 static VALUE
 rb_ary_replace(VALUE copy, VALUE orig)
 {
-    VALUE shared;
-
     rb_ary_modify(copy);
     orig = to_ary(orig);
     if (copy == orig) return copy;
-    shared = ary_make_shared(orig);
-    if (RARRAY(copy)->ptr && !FL_TEST(copy, ELTS_SHARED))
-	free(RARRAY(copy)->ptr);
-    RARRAY(copy)->ptr = RARRAY(orig)->ptr;
-    RARRAY(copy)->len = RARRAY(orig)->len;
-    RARRAY(copy)->aux.shared = shared;
-    FL_SET(copy, ELTS_SHARED);
+    ary_free(copy);
+    ary_share(copy,orig);
 
     return copy;
 }
@@ -2060,12 +2278,19 @@
 VALUE
 rb_ary_clear(VALUE ary)
 {
+    long capa;
     rb_ary_modify(ary);
+    capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
     RARRAY(ary)->len = 0;
-    if (ARY_DEFAULT_SIZE * 2 < RARRAY(ary)->aux.capa) {
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, ARY_DEFAULT_SIZE * 2);
-	RARRAY(ary)->aux.capa = ARY_DEFAULT_SIZE * 2;
+    if (ARY_DEFAULT_SIZE * 2 < capa) {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, ARY_DEFAULT_SIZE * 2 + lfree);
+        RARRAY(ary)->ptr += lfree;
+	capa = ARY_DEFAULT_SIZE * 2;
     }
+    RARRAY(ary)->ptr[0] = capa;
+    FL_SET(ary,ELTS_RFREE);
     return ary;
 }
 
@@ -2131,13 +2356,23 @@
     rb_ary_modify(ary);
     end = beg + len;
     if (end > RARRAY(ary)->len) {
-	if (end >= RARRAY(ary)->aux.capa) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, end);
-	    RARRAY(ary)->aux.capa = end;
+        long capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
+	if (end >= capa) {
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            RARRAY(ary)->ptr -= lfree;
+	    REALLOC_N(RARRAY(ary)->ptr, VALUE, end + lfree);
+            RARRAY(ary)->ptr += lfree;
+	    capa = end;
 	}
 	if (beg > RARRAY(ary)->len) {
 	    rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, end - RARRAY(ary)->len);
 	}
+        if (capa > end) {
+            RARRAY(ary)->ptr[end] = capa-end;
+            FL_SET(ary,ELTS_RFREE);
+        } else {
+            FL_UNSET(ary,ELTS_RFREE);
+        }
 	RARRAY(ary)->len = end;
     }
 
@@ -2611,6 +2846,7 @@
 {
     VALUE hash, v, vv;
     long i, j;
+    long capa;
 
     hash = ary_make_hash(ary, 0);
 
@@ -2623,7 +2859,14 @@
 	    rb_ary_store(ary, j++, v);
 	}
     }
+    capa = RARRAY(ary)->len+(FL_TEST(ary,ELTS_RFREE) ? RARRAY(ary)->ptr[RARRAY(ary)->len] : 0);
     RARRAY(ary)->len = j;
+    if (capa > j) {
+        RARRAY(ary)->ptr[j] = capa-j;
+        FL_SET(ary,ELTS_RFREE);
+    } else {
+        FL_UNSET(ary,ELTS_RFREE);
+    }
 
     return ary;
 }
@@ -2661,6 +2904,7 @@
 rb_ary_compact_bang(VALUE ary)
 {
     VALUE *p, *t, *end;
+    long lfree;
 
     rb_ary_modify(ary);
     p = t = RARRAY(ary)->ptr;
@@ -2673,8 +2917,12 @@
     if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) {
 	return Qnil;
     }
-    RARRAY(ary)->len = RARRAY(ary)->aux.capa = (p - RARRAY(ary)->ptr);
-    REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
+    RARRAY(ary)->len = (p - RARRAY(ary)->ptr);
+    lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+    RARRAY(ary)->ptr -= lfree;
+    REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len + lfree);
+    RARRAY(ary)->ptr += lfree;
+    FL_UNSET(ary,ELTS_RFREE);
 
     return ary;
 }
Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.209
diff -u -r1.209 gc.c
--- gc.c	14 Sep 2005 08:30:15 -0000	1.209
+++ gc.c	21 Sep 2005 16:13:05 -0000
@@ -711,7 +711,7 @@
     obj->as.basic.flags |= FL_MARK;
 
   marking:
-    if (FL_TEST(obj, FL_EXIVAR)) {
+    if (FL_TEST(obj, FL_EXIVAR)) {      
 	rb_mark_generic_ivar(ptr);
     }
 
@@ -869,11 +869,7 @@
 	goto again;
 
       case T_ARRAY:
-	if (FL_TEST(obj, ELTS_SHARED)) {
-	    ptr = obj->as.array.aux.shared;
-	    goto again;
-	}
-	else {
+	{
 	    long i, len = obj->as.array.len;
 	    VALUE *ptr = obj->as.array.ptr;
 
@@ -1110,9 +1106,7 @@
 	}
 	break;
       case T_ARRAY:
-	if (RANY(obj)->as.array.ptr && !FL_TEST(obj, ELTS_SHARED)) {
-	    RUBY_CRITICAL(free(RANY(obj)->as.array.ptr));
-	}
+	ary_free(obj);
 	break;
       case T_HASH:
 	if (RANY(obj)->as.hash.tbl) {
Index: ruby.h
===================================================================
RCS file: /src/ruby/ruby.h,v
retrieving revision 1.122
diff -u -r1.122 ruby.h
--- ruby.h	14 Sep 2005 13:40:43 -0000	1.122
+++ ruby.h	21 Sep 2005 16:13:05 -0000
@@ -346,7 +346,10 @@
     double value;
 };
 
+// SHARED implies not (LFREE or RFREE)
 #define ELTS_SHARED FL_USER2
+#define ELTS_LFREE FL_USER3
+#define ELTS_RFREE FL_USER4
 
 struct RString {
     struct RBasic basic;
@@ -361,10 +364,7 @@
 struct RArray {
     struct RBasic basic;
     long len;
-    union {
-	long capa;
 	VALUE shared;
-    } aux;
     VALUE *ptr;
 };
 
end_test.rb (3.72 KB, text/x-ruby)
require 'benchmark'

#init final code element-assertion

tests = %w{

1   1   ;                               i
        
1.5 0.5 shift                           i+n
1.5 0.5 shift(1)                        i+n
1.5 0.5 pop                             i
1.5 0.5 pop(1)                          i
2   0   shift;pop                       nil
2   0   shift(1);pop(1)                 nil
        
0.5 1.5 unshift(i)                      (i>=n)&&(i-n)||(n-1-i)
0.5 1.5 push(i)                         (i>=n/2)&&(i-n/2)||i
0   2   unshift(i);push(i)              (i>=n)&&(i-n)||(n-1-i)
        
1   1   unshift(shift)                  i
1   1   unshift(*shift(1))              i
1   1   push(pop)                       i
1   1   push(*pop(1))                   i
1   1   push(shift)                     i
1   1   push(*shift(1))                 i
1   1   unshift(pop)                    i
1   1   unshift(*pop(1))                i
        
1.5 0.5 slice!(1)                       (i<1)&&i||(i+n)
1.5 0.5 delete_at(1)                    (i<1)&&i||(i+n)
1.5 0.5 slice!(1,1)                     (i<1)&&i||(i+n)
1.5 0.5 self[1,1]=[]                    (i<1)&&i||(i+n)
1.5 0.5 slice!(-2)                      (i>n/2-2)&&(i+n)||i
1.5 0.5 delete_at(-2)                   (i>n/2-2)&&(i+n)||i
1.5 0.5 slice!(-2,1)                    (i>n/2-2)&&(i+n)||i
1.5 0.5 self[-2,1]=[]                   (i>n/2-2)&&(i+n)||i
        
0.5 1.5 self[1,0]=[i]                   j=n-i;(j<0)&&(i-n)||(j>=n)&&i||j
0.5 1.5 insert(1,i)                     j=n-i;(j<0)&&(i-n)||(j>=n)&&i||j
0.5 1.5 self[-1,0]=[i]                  j=i-n/2+1;(j<0)&&i||(j>=n)&&(i-n)||j
0.5 1.5 insert(-2,i)                    j=i-n/2+1;(j<0)&&i||(j>=n)&&(i-n)||j

1   1   self[1,0]=slice!(1,1)           i
1   1   insert(1,delete_at(1))          i
1   1   self[-1,0]=slice!(-2,1)         i
1   1   insert(-2,delete_at(-2))        i

1   1   self[-1,0]=slice!(1,1)          ((i<1)||(i>=n-1))&&i||((i+1)%(n-2)+1)
1   1   insert(-2,delete_at(1))         ((i<1)||(i>=n-1))&&i||((i+1)%(n-2)+1)
1   1   self[1,0]=slice!(-2,1)          ((i<1)||(i>=n-1))&&i||((i-3)%(n-2)+1)
1   1   insert(1,delete_at(-2))         ((i<1)||(i>=n-1))&&i||((i-3)%(n-2)+1)

1   1   self[i]=self[i]                 i
1   1   self[i]=at(i)                   i
1   1   self[i,1]=self[i,1]             i
1   1   self[-i-1]=self[-i-1]           i
1   1   self[-i-1]=at(-i-1)             i
1   1   self[-i-1,1]=self[-i-1,1]       i
1   1   self[-i-1]=self[i]              (i>=n/2)&&(n-1-i)||i
1   1   self[-i-1]=at(i)                (i>=n/2)&&(n-1-i)||i
1   1   self[-i-1,1]=self[i,1]          (i>=n/2)&&(n-1-i)||i
1   1   self[i]=self[-i-1]              (i>=n/2)&&i||(n-1-i)
1   1   self[i]=at(-i-1)                (i>=n/2)&&i||(n-1-i)
1   1   self[i,1]=self[-i-1,1]          (i>=n/2)&&i||(n-1-i)

}

Fields = 4

ARGV.replace([12]) if ARGV.empty?

ARGV.each { |exp|
    n = 1 << exp.to_i
    puts
    puts("n = #{n}")
    an = (0...(n << 1)).to_a
    
    results = Hash.new;
    Benchmark.bmbm { |benchmark|
        entry = 0   
        while entry<tests.size
            init,final,code,assert = tests[entry,Fields]
            #puts(code)
            init = init.to_f
            final = final.to_f
            init+final==2 or raise(init.to_s+"+"+final.to_s+"!=2");
            results[entry/Fields] = final==0 ? [] :
                eval("Array.new(#{(n*final).to_i}) {|i|
                    #{assert}
                }")
            benchmark.report(code,&eval("lambda {
                a = an[0,#{(n*init).to_i}]
                a.instance_eval {#{n}.times{ |i|
                    #{code}
                }}
                result = results[#{entry/Fields}]
                a==result or raise(a.inspect+'!='+result.inspect)
            }"))
            entry += Fields
        end
    }
}


In This Thread

Prev Next