Author: Armin Rigo <ar...@tunes.org>
Branch: array-overallocation-in-nursery
Changeset: r67804:30af5046d2b3
Date: 2013-11-03 08:47 +0100
http://bitbucket.org/pypy/pypy/changeset/30af5046d2b3/

Log:    Use GcArray(overallocated=True) in rlist.py.

diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -200,13 +200,15 @@
 
     # supports non-overlapping copies only
     if not we_are_translated():
-        if source == dest:
+        if lltype.typeOf(source) == lltype.typeOf(dest) and source == dest:
             assert (source_start + length <= dest_start or
                     dest_start + length <= source_start)
 
-    TP = lltype.typeOf(source).TO
-    assert TP == lltype.typeOf(dest).TO
-    if _contains_gcptr(TP.OF):
+    # supports copying between an overallocated GcArray and a regular GcArray
+    TP_SRC = lltype.typeOf(source).TO
+    TP_DST = lltype.typeOf(dest).TO
+    assert TP_SRC.OF == TP_DST.OF
+    if _contains_gcptr(TP_SRC.OF):
         # perform a write barrier that copies necessary flags from
         # source to dest
         if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest,
@@ -220,13 +222,13 @@
             return
     source_addr = llmemory.cast_ptr_to_adr(source)
     dest_addr   = llmemory.cast_ptr_to_adr(dest)
-    cp_source_addr = (source_addr + llmemory.itemoffsetof(TP, 0) +
-                      llmemory.sizeof(TP.OF) * source_start)
-    cp_dest_addr = (dest_addr + llmemory.itemoffsetof(TP, 0) +
-                    llmemory.sizeof(TP.OF) * dest_start)
+    cp_source_addr = (source_addr + llmemory.itemoffsetof(TP_SRC, 0) +
+                      llmemory.sizeof(TP_SRC.OF) * source_start)
+    cp_dest_addr = (dest_addr + llmemory.itemoffsetof(TP_DST, 0) +
+                    llmemory.sizeof(TP_DST.OF) * dest_start)
 
     llmemory.raw_memcopy(cp_source_addr, cp_dest_addr,
-                         llmemory.sizeof(TP.OF) * length)
+                         llmemory.sizeof(TP_SRC.OF) * length)
     keepalive_until_here(source)
     keepalive_until_here(dest)
 
diff --git a/rpython/rtyper/lltypesystem/rlist.py 
b/rpython/rtyper/lltypesystem/rlist.py
--- a/rpython/rtyper/lltypesystem/rlist.py
+++ b/rpython/rtyper/lltypesystem/rlist.py
@@ -54,8 +54,11 @@
         else:
             raise NotImplementedError(variant)
 
-    def get_itemarray_lowleveltype(self):
+    def get_itemarray_lowleveltype(self, overallocated):
         ITEM = self.item_repr.lowleveltype
+        hints = {}
+        if overallocated:
+            hints['overallocated'] = True
         ITEMARRAY = GcArray(ITEM,
                             adtmeths = ADTIFixedList({
                                  "ll_newlist": ll_fixed_newlist,
@@ -65,7 +68,8 @@
                                  "ITEM": ITEM,
                                  "ll_getitem_fast": ll_fixed_getitem_fast,
                                  "ll_setitem_fast": ll_fixed_setitem_fast,
-                            }))
+                            }),
+                            hints = hints)
         return ITEMARRAY
 
 
@@ -86,10 +90,9 @@
             self.external_item_repr, self.item_repr = 
externalvsinternal(self.rtyper, self._item_repr_computer())
         if isinstance(self.LIST, GcForwardReference):
             ITEM = self.item_repr.lowleveltype
-            ITEMARRAY = self.get_itemarray_lowleveltype()
+            ITEMARRAY = self.get_itemarray_lowleveltype(True)
             # XXX we might think of turning length stuff into Unsigned
-            self.LIST.become(GcStruct("list", ("length", Signed),
-                                              ("items", Ptr(ITEMARRAY)),
+            self.LIST.become(GcStruct("list", ("items", Ptr(ITEMARRAY)),
                                       adtmeths = ADTIList({
                                           "ll_newlist": ll_newlist,
                                           "ll_newlist_hint": ll_newlist_hint,
@@ -112,8 +115,8 @@
 
     def prepare_const(self, n):
         result = malloc(self.LIST, immortal=True)
-        result.length = n
         result.items = malloc(self.LIST.items.TO, n)
+        result.items.used_length = n
         return result
 
 
@@ -123,7 +126,7 @@
         if 'item_repr' not in self.__dict__:
             self.external_item_repr, self.item_repr = 
externalvsinternal(self.rtyper, self._item_repr_computer())
         if isinstance(self.LIST, GcForwardReference):
-            ITEMARRAY = self.get_itemarray_lowleveltype()
+            ITEMARRAY = self.get_itemarray_lowleveltype(overallocated=False)
             self.LIST.become(ITEMARRAY)
 
     def compact_repr(self):
@@ -142,12 +145,14 @@
 
 # adapted C code
 
-@jit.look_inside_iff(lambda l, newsize, overallocate: 
jit.isconstant(len(l.items)) and jit.isconstant(newsize))
+@jit.look_inside_iff(lambda l, newsize, overallocate:
+                     jit.isconstant(l.items.allocated_length) and
+                     jit.isconstant(newsize))
 @signature(types.any(), types.int(), types.bool(), returns=types.none())
 def _ll_list_resize_hint_really(l, newsize, overallocate):
     """
     Ensure l.items has room for at least newsize elements.  Note that
-    l.items may change, and even if newsize is less than l.length on
+    l.items may change, and even if newsize is less than used_length on
     entry.
     """
     # This over-allocates proportional to the list size, making room
@@ -158,7 +163,6 @@
     # The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
     if newsize <= 0:
         ll_assert(newsize == 0, "negative list length")
-        l.length = 0
         l.items = _ll_new_empty_item_array(typeOf(l).TO)
         return
     elif overallocate:
@@ -174,28 +178,28 @@
     # linear complexity for e.g. repeated usage of l.append().  In case
     # it overflows sys.maxint, it is guaranteed negative, and the following
     # malloc() will fail.
+    newitems = malloc(typeOf(l).TO.items.TO, new_allocated)
     items = l.items
-    newitems = malloc(typeOf(l).TO.items.TO, new_allocated)
-    before_len = l.length
+    before_len = items.used_length
     if before_len:   # avoids copying GC flags from the prebuilt_empty_array
-        if before_len < newsize:
-            p = before_len
-        else:
-            p = newsize
+        p = min(before_len, newsize)
+        newitems.used_length = p
         rgc.ll_arraycopy(items, newitems, 0, 0, p)
     l.items = newitems
 
-@jit.look_inside_iff(lambda l, newsize: jit.isconstant(len(l.items)) and 
jit.isconstant(newsize))
+@jit.look_inside_iff(lambda l, newsize:
+                     jit.isconstant(l.items.allocated_length) and
+                     jit.isconstant(newsize))
 def _ll_list_resize_hint(l, newsize):
     """Ensure l.items has room for at least newsize elements without
-    setting l.length to newsize.
+    setting used_length to newsize.
 
     Used before (and after) a batch operation that will likely grow the
     list to the newsize (and after the operation incase the initial
     guess lied).
     """
     assert newsize >= 0, "negative list length"
-    allocated = len(l.items)
+    allocated = l.items.allocated_length
     if newsize > allocated:
         overallocate = True
     elif newsize < (allocated >> 1) - 5:
@@ -208,11 +212,11 @@
 def _ll_list_resize_really(l, newsize, overallocate):
     """
     Ensure l.items has room for at least newsize elements, and set
-    l.length to newsize.  Note that l.items may change, and even if
-    newsize is less than l.length on entry.
+    used_length to newsize.  Note that l.items may change, and even if
+    newsize is less than used_length on entry.
     """
     _ll_list_resize_hint_really(l, newsize, overallocate)
-    l.length = newsize
+    l.items.used_length = newsize
 
 # this common case was factored out of _ll_list_resize
 # to see if inlining it gives some speed-up.
@@ -230,34 +234,30 @@
     a realloc().  In the common case where we already overallocated enough,
     then this is a very fast operation.
     """
-    cond = len(l.items) < newsize
-    if jit.isconstant(len(l.items)) and jit.isconstant(newsize):
+    allocated = l.items.allocated_length
+    cond = allocated < newsize
+    if jit.isconstant(allocated) and jit.isconstant(newsize):
         if cond:
             _ll_list_resize_hint_really(l, newsize, True)
     else:
         jit.conditional_call(cond,
                              _ll_list_resize_hint_really, l, newsize, True)
-    l.length = newsize
+    l.items.used_length = newsize
 
 def _ll_list_resize_le(l, newsize):
     """This is called with 'newsize' smaller than the current length of the
     list.  If 'newsize' falls lower than half the allocated size, proceed
     with the realloc() to shrink the list.
     """
-    cond = newsize < (len(l.items) >> 1) - 5
+    cond = newsize < (l.items.allocated_length >> 1) - 5
     # note: overallocate=False should be safe here
-    if jit.isconstant(len(l.items)) and jit.isconstant(newsize):
+    if jit.isconstant(l.items.allocated_length) and jit.isconstant(newsize):
         if cond:
             _ll_list_resize_hint_really(l, newsize, False)
     else:
         jit.conditional_call(cond, _ll_list_resize_hint_really, l, newsize,
                              False)
-    l.length = newsize
-
-def ll_append_noresize(l, newitem):
-    length = l.length
-    l.length = length + 1
-    l.ll_setitem_fast(length, newitem)
+    l.items.used_length = newsize
 
 
 def ll_both_none(lst1, lst2):
@@ -271,8 +271,9 @@
 def ll_newlist(LIST, length):
     ll_assert(length >= 0, "negative list length")
     l = malloc(LIST)
-    l.length = length
-    l.items = malloc(LIST.items.TO, length)
+    items = malloc(LIST.items.TO, length)
+    items.used_length = length
+    l.items = items
     return l
 ll_newlist = typeMethod(ll_newlist)
 ll_newlist.oopspec = 'newlist(length)'
@@ -280,7 +281,6 @@
 def ll_newlist_hint(LIST, lengthhint):
     ll_assert(lengthhint >= 0, "negative list length")
     l = malloc(LIST)
-    l.length = 0
     l.items = malloc(LIST.items.TO, lengthhint)
     return l
 ll_newlist_hint = typeMethod(ll_newlist_hint)
@@ -292,7 +292,7 @@
 INITIAL_EMPTY_LIST_ALLOCATION = 0
 
 def _ll_prebuilt_empty_array(LISTITEM):
-    return malloc(LISTITEM, 0)
+    return malloc(LISTITEM, 0)     # memo!
 _ll_prebuilt_empty_array._annspecialcase_ = 'specialize:memo'
 
 def _ll_new_empty_item_array(LIST):
@@ -303,26 +303,25 @@
 
 def ll_newemptylist(LIST):
     l = malloc(LIST)
-    l.length = 0
     l.items = _ll_new_empty_item_array(LIST)
     return l
 ll_newemptylist = typeMethod(ll_newemptylist)
 ll_newemptylist.oopspec = 'newlist(0)'
 
 def ll_length(l):
-    return l.length
+    return l.items.used_length
 ll_length.oopspec = 'list.len(l)'
 
 def ll_items(l):
     return l.items
 
 def ll_getitem_fast(l, index):
-    ll_assert(index < l.length, "getitem out of bounds")
+    ll_assert(index < l.ll_length(), "getitem out of bounds")
     return l.ll_items()[index]
 ll_getitem_fast.oopspec = 'list.getitem(l, index)'
 
 def ll_setitem_fast(l, index, item):
-    ll_assert(index < l.length, "setitem out of bounds")
+    ll_assert(index < l.ll_length(), "setitem out of bounds")
     l.ll_items()[index] = item
 ll_setitem_fast.oopspec = 'list.setitem(l, index, item)'
 
@@ -405,7 +404,7 @@
     index = iter.index
     if index >= l.ll_length():
         raise StopIteration
-    iter.index = index + 1      # cannot overflow because index < l.length
+    iter.index = index + 1      # cannot overflow because index < used_length
     return l.ll_getitem_fast(index)
 
 def ll_listnext_foldable(iter):
@@ -414,7 +413,7 @@
     index = iter.index
     if index >= l.ll_length():
         raise StopIteration
-    iter.index = index + 1      # cannot overflow because index < l.length
+    iter.index = index + 1      # cannot overflow because index < used_length
     return ll_getitem_foldable_nonneg(l, index)
 
 def ll_getnextindex(iter):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to