Author: Armin Rigo <[email protected]>
Branch: array-overallocation-in-nursery
Changeset: r67503:0422d725e21c
Date: 2013-10-22 12:45 +0200
http://bitbucket.org/pypy/pypy/changeset/0422d725e21c/

Log:    (fijal, arigo)

        Support llmemory.ArrayLengthOffset to point to the two kinds of
        lengths

diff --git a/rpython/rtyper/lltypesystem/llmemory.py 
b/rpython/rtyper/lltypesystem/llmemory.py
--- a/rpython/rtyper/lltypesystem/llmemory.py
+++ b/rpython/rtyper/lltypesystem/llmemory.py
@@ -306,8 +306,15 @@
 
 class ArrayLengthOffset(AddressOffset):
 
-    def __init__(self, TYPE):
+    def __init__(self, TYPE, attrkind="length"):
+        assert isinstance(TYPE, lltype.Array)
+        assert not TYPE._hints.get('nolength', False)
+        if attrkind == "length":
+            assert not TYPE._is_overallocated_array()
+        else:
+            assert TYPE._is_overallocated_array()
         self.TYPE = TYPE
+        self.attrkind = attrkind
 
     def __repr__(self):
         return '< ArrayLengthOffset %r >' % (self.TYPE,)
@@ -317,7 +324,8 @@
 
     def ref(self, arrayptr):
         assert array_type_match(lltype.typeOf(arrayptr).TO, self.TYPE)
-        return lltype._arraylenref._makeptr(arrayptr._obj, arrayptr._solid)
+        return lltype._arraylenref._makeptr(arrayptr._obj, arrayptr._solid,
+                                            self.attrkind)
 
 
 class GCHeaderOffset(AddressOffset):
diff --git a/rpython/rtyper/lltypesystem/lltype.py 
b/rpython/rtyper/lltypesystem/lltype.py
--- a/rpython/rtyper/lltypesystem/lltype.py
+++ b/rpython/rtyper/lltypesystem/lltype.py
@@ -1192,13 +1192,7 @@
                 return
         if self._T._is_overallocated_array():
             if field_name == 'used_length':
-                if val > self._obj.getlength():
-                    raise ValueError("overallocated array size is %s, trying "
-                                     "to set used size to %s" %
-                                     (self._obj.getlength(), val))
-                for i in range(val, self._obj.used_len):
-                    self._obj.items[i] = self._T.OF._allocate('malloc')
-                self._obj.used_len = val
+                self._obj.set_used_length(val)
                 return
         raise AttributeError("%r instance has no field %r" % (self._T,
                                                               field_name))
@@ -1755,6 +1749,16 @@
         assert typeOf(value) == self._TYPE.OF
         self.items[index] = value
 
+    def set_used_length(self, val):
+        assert self._TYPE._is_overallocated_array()
+        if val > self.getlength():
+            raise ValueError("overallocated array size is %s, trying "
+                             "to set used size to %s" %
+                             (self.getlength(), val))
+        for i in range(val, self.used_len):
+            self.items[i] = self._TYPE.OF._allocate('malloc')
+        self.used_len = val
+
 assert not '__dict__' in dir(_struct)
 
 
@@ -1868,12 +1872,18 @@
     Only used internally by llmemory to implement ArrayLengthOffset.
     """
     _kind = "arraylenptr"
-    _cache = weakref.WeakKeyDictionary()  # array -> _arraylenref
+    _cache = {
+        "length": weakref.WeakKeyDictionary(),  # array -> _arraylenref
+        "allocated_length": weakref.WeakKeyDictionary(),
+        "used_length": weakref.WeakKeyDictionary(),
+        }
 
-    def __init__(self, array):
+    def __init__(self, array, attrkind):
         TYPE = FixedSizeArray(Signed, 1)
         _parentable.__init__(self, TYPE)
         self.array = array
+        self.attrkind = attrkind
+        assert attrkind in self._cache
 
     def getlength(self):
         return 1
@@ -1883,23 +1893,34 @@
 
     def getitem(self, index, uninitialized_ok=False):
         assert index == 0
-        return self.array.getlength()
+        if self.attrkind == "length":
+            return self.array.getlength()
+        elif self.attrkind == "allocated_length":
+            return len(self.array.items)
+        elif self.attrkind == "used_length":
+            return self.array.used_len
 
     def setitem(self, index, value):
         assert index == 0
-        if value != self.array.getlength():
-            if value > self.array.getlength():
-                raise Exception("can't grow an array in-place")
-            self.array.shrinklength(value)
+        if self.attrkind == "length":
+            if value != self.array.getlength():
+                if value > self.array.getlength():
+                    raise Exception("can't grow an array in-place")
+                self.array.shrinklength(value)
+        elif self.attrkind == "allocated_length":
+            raise Exception("can't set allocated_length")
+        elif self.attrkind == "used_length":
+            self.array.set_used_length(value)
 
-    def _makeptr(array, solid=False):
+    @staticmethod
+    def _makeptr(array, solid=False, attrkind="length"):
+        cache = _arraylenref._cache[attrkind]
         try:
-            lenref = _arraylenref._cache[array]
+            lenref = cache[array]
         except KeyError:
-            lenref = _arraylenref(array)
-            _arraylenref._cache[array] = lenref
+            lenref = _arraylenref(array, attrkind)
+            cache[array] = lenref
         return _ptr(Ptr(lenref._TYPE), lenref, solid)
-    _makeptr = staticmethod(_makeptr)
 
     def _getid(self):
         raise NotImplementedError('_arraylenref._getid()')
diff --git a/rpython/rtyper/lltypesystem/test/test_llmemory.py 
b/rpython/rtyper/lltypesystem/test/test_llmemory.py
--- a/rpython/rtyper/lltypesystem/test/test_llmemory.py
+++ b/rpython/rtyper/lltypesystem/test/test_llmemory.py
@@ -649,3 +649,16 @@
     #assert cast_int_to_adr(i) == adr -- depends on ll2ctypes details
     i = cast_adr_to_int(NULL, mode="forced")
     assert is_valid_int(i) and i == 0
+
+def test_overallocated_array():
+    A = lltype.GcArray(lltype.Signed, hints={'overallocated': True})
+    a = lltype.malloc(A, 10)
+    adr = cast_ptr_to_adr(a)
+    py.test.raises(AssertionError, ArrayLengthOffset, A)
+    length_adr = adr + ArrayLengthOffset(A, "allocated_length")
+    assert length_adr.signed[0] == 10
+    length_adr = adr + ArrayLengthOffset(A, "used_length")
+    assert length_adr.signed[0] == 0
+    #
+    length_adr.signed[0] = 2
+    assert a.used_length == 2
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to