[pypy-commit] pypy default: Attempt to fix generally the issue of VStringPlainValue that can

arigo noreply at buildbot.pypy.org
Fri Nov 4 11:48:23 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r48742:4c8fd4b0ca57
Date: 2011-11-04 11:43 +0100
http://bitbucket.org/pypy/pypy/changeset/4c8fd4b0ca57/

Log:	Attempt to fix generally the issue of VStringPlainValue that can be
	forced before being fully built --- e.g. because it's a target of a
	copystrcontent. I think this fix is all that it needed, but in case
	I missed a place, then it will end up with an AssertionError or a
	segfault (self._chars is None) at run-time, instead of producing
	bogus results.

diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -113,6 +113,33 @@
     """A string built with newstr(const)."""
     _lengthbox = None     # cache only
 
+    # Warning: an issue with VStringPlainValue is that sometimes it is
+    # initialized unpredictably by some copystrcontent.  When this occurs
+    # we set self._chars to None.  Be careful to check for is_valid().
+
+    def is_valid(self):
+        return self._chars is not None
+
+    def _invalidate(self):
+        assert self.is_valid()
+        if self._lengthbox is None:
+            self._lengthbox = ConstInt(len(self._chars))
+        self._chars = None
+
+    def _really_force(self, optforce):
+        VAbstractStringValue._really_force(self, optforce)
+        assert self.box is not None
+        if self.is_valid():
+            for c in self._chars:
+                if c is optimizer.CVAL_UNINITIALIZED_ZERO:
+                    # the string has uninitialized null bytes in it, so
+                    # assume that it is forced for being further mutated
+                    # (e.g. by copystrcontent).  So it becomes invalid
+                    # as a VStringPlainValue: the _chars must not be used
+                    # any longer.
+                    self._invalidate()
+                    break
+
     def setup(self, size):
         self._chars = [optimizer.CVAL_UNINITIALIZED_ZERO] * size
 
@@ -134,6 +161,8 @@
 
     @specialize.arg(1)
     def get_constant_string_spec(self, mode):
+        if not self.is_valid():
+            return None
         for c in self._chars:
             if c is optimizer.CVAL_UNINITIALIZED_ZERO or not c.is_constant():
                 return None
@@ -141,11 +170,9 @@
                                    for c in self._chars])
 
     def string_copy_parts(self, string_optimizer, targetbox, offsetbox, mode):
-        if not self.is_virtual() and targetbox is not self.box:
-            lengthbox = self.getstrlen(string_optimizer, mode)
-            srcbox = self.force_box(string_optimizer)
-            return copy_str_content(string_optimizer, srcbox, targetbox,
-                                CONST_0, offsetbox, lengthbox, mode)
+        if not self.is_valid():
+            return VAbstractStringValue.string_copy_parts(
+                self, string_optimizer, targetbox, offsetbox, mode)
         for i in range(len(self._chars)):
             charbox = self._chars[i].force_box(string_optimizer)
             if not (isinstance(charbox, Const) and charbox.same_constant(CONST_0)):
@@ -158,6 +185,7 @@
 
     def get_args_for_fail(self, modifier):
         if self.box is None and not modifier.already_seen_virtual(self.keybox):
+            assert self.is_valid()
             charboxes = [value.get_key_box() for value in self._chars]
             modifier.register_virtual_fields(self.keybox, charboxes)
             for value in self._chars:
@@ -373,7 +401,8 @@
 
     def optimize_STRSETITEM(self, op):
         value = self.getvalue(op.getarg(0))
-        if value.is_virtual() and isinstance(value, VStringPlainValue):
+        if (value.is_virtual() and isinstance(value, VStringPlainValue)
+            and value.is_valid()):
             indexbox = self.get_constant_box(op.getarg(1))
             if indexbox is not None:
                 value.setitem(indexbox.getint(), self.getvalue(op.getarg(2)))
@@ -404,13 +433,10 @@
             value = value.vstr
             vindex = self.getvalue(fullindexbox)
         #
-        if isinstance(value, VStringPlainValue):  # even if no longer virtual
+        if (isinstance(value, VStringPlainValue)  # even if no longer virtual
+            and value.is_valid()):                # but make sure it is valid
             if vindex.is_constant():
-                res = value.getitem(vindex.box.getint())
-                # If it is uninitialized we can't return it, it was set by a
-                # COPYSTRCONTENT, not a STRSETITEM
-                if res is not optimizer.CVAL_UNINITIALIZED_ZERO:
-                    return res
+                return value.getitem(vindex.box.getint())
         #
         resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode)
         return self.getvalue(resbox)
@@ -503,19 +529,12 @@
         vstart = self.getvalue(op.getarg(2))
         vstop = self.getvalue(op.getarg(3))
         #
-        if (isinstance(vstr, VStringPlainValue) and vstart.is_constant()
-            and vstop.is_constant()):
-            # slicing with constant bounds of a VStringPlainValue, if any of
-            # the characters is unitialized we don't do this special slice, we
-            # do the regular copy contents.
-            for i in range(vstart.box.getint(), vstop.box.getint()):
-                if vstr.getitem(i) is optimizer.CVAL_UNINITIALIZED_ZERO:
-                    break
-            else:
-                value = self.make_vstring_plain(op.result, op, mode)
-                value.setup_slice(vstr._chars, vstart.box.getint(),
-                                               vstop.box.getint())
-                return True
+        if (isinstance(vstr, VStringPlainValue) and vstr.is_valid()
+            and vstart.is_constant() and vstop.is_constant()):
+            value = self.make_vstring_plain(op.result, op, mode)
+            value.setup_slice(vstr._chars, vstart.box.getint(),
+                              vstop.box.getint())
+            return True
         #
         vstr.ensure_nonnull()
         lengthbox = _int_sub(self, vstop.force_box(self),


More information about the pypy-commit mailing list