Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: guard-compatible Changeset: r85324:914cc74b5a8c Date: 2016-06-20 15:49 +0200 http://bitbucket.org/pypy/pypy/changeset/914cc74b5a8c/
Log: merge default diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -26,3 +26,4 @@ 40497617ae91caa1a394d8be6f9cd2de31cb0628 release-pypy3.3-v5.2 40497617ae91caa1a394d8be6f9cd2de31cb0628 release-pypy3.3-v5.2 c09c19272c990a0611b17569a0085ad1ab00c8ff release-pypy2.7-v5.3 +7e8df3df96417c16c2d55b41352ec82c9c69c978 release-pypy2.7-v5.3.1 diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.9 +Version: 0.4.10 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.9" +__version__ = "0.4.10" # ____________________________________________________________ # Exceptions diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -315,13 +315,28 @@ - ``complex`` + - ``str`` (empty or single-character strings only) + + - ``unicode`` (empty or single-character strings only) + + - ``tuple`` (empty tuples only) + + - ``frozenset`` (empty frozenset only) + This change requires some changes to ``id`` as well. ``id`` fulfills the following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the above types will return a value that is computed from the argument, and can thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long). -Notably missing from the list above are ``str`` and ``unicode``. If your -code relies on comparing strings with ``is``, then it might break in PyPy. +Note that strings of length 2 or greater can be equal without being +identical. Similarly, ``x is (2,)`` is not necessarily true even if +``x`` contains a tuple and ``x == (2,)``. The uniqueness rules apply +only to the particular cases described above. The ``str``, ``unicode``, +``tuple`` and ``frozenset`` rules were added in PyPy 5.4; before that, a +test like ``if x is "?"`` or ``if x is ()`` could fail even if ``x`` was +equal to ``"?"`` or ``()``. The new behavior added in PyPy 5.4 is +closer to CPython's, which caches precisely the empty tuple/frozenset, +and (generally but not always) the strings and unicodes of length <= 1. Note that for floats there "``is``" only one object per "bit pattern" of the float. So ``float('nan') is float('nan')`` is true on PyPy, diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-pypy2.7-v5.3.1.rst release-pypy2.7-v5.3.0.rst release-5.1.1.rst release-5.1.0.rst diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst --- a/pypy/doc/index-of-whatsnew.rst +++ b/pypy/doc/index-of-whatsnew.rst @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-pypy2-5.3.1.rst whatsnew-pypy2-5.3.0.rst whatsnew-5.1.0.rst whatsnew-5.0.0.rst diff --git a/pypy/doc/release-pypy2.7-v5.3.1.rst b/pypy/doc/release-pypy2.7-v5.3.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-pypy2.7-v5.3.1.rst @@ -0,0 +1,41 @@ +========== +PyPy 5.3.1 +========== + +We have released a bugfix for PyPy2.7-v5.3.0, released last week, +due to issues_ reported by users. + +Thanks to those who reported the issues. + +.. _issues: http://doc.pypy.org/en/latest/whatsnew-pypy2-5.3.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +This release supports: + + * **x86** machines on most common operating systems + (Linux 32/64, Mac OS X 64, Windows 32, OpenBSD, FreeBSD), + + * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + +.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://pypyjs.org + +Please update, and continue to help us make PyPy better. + +Cheers + +The PyPy Team + diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -5,6 +5,10 @@ .. this is a revision shortly after release-pypy2.7-v5.3 .. startrev: 873218a739f1 +.. 418b05f95db5 +Improve CPython compatibility for ``is``. Now code like ``if x is ():`` +works the same way as it does on CPython. See http://pypy.readthedocs.io/en/latest/cpython_differences.html#object-identity-of-primitive-values-is-and-id . + .. pull request #455 Add sys.{get,set}dlopenflags, for cpyext extensions. @@ -31,3 +35,5 @@ Simplify handling of interp-level tests and make it more forward- compatible. +.. branch: pyfile-tell +Sync w_file with the c-level FILE* before returning FILE* in PyFile_AsFile diff --git a/pypy/doc/whatsnew-pypy2-5.3.1.rst b/pypy/doc/whatsnew-pypy2-5.3.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-pypy2-5.3.1.rst @@ -0,0 +1,15 @@ +=========================== +What's new in PyPy2.7 5.3.1 +=========================== + +.. this is a revision shortly after release-pypy2.7-v5.3.0 +.. startrev: f4d726d1a010 + + +A bug-fix release, merging these changes: + + * Add include guards to pymem.h, fixes issue #2321 + + * Make vmprof build on OpenBSD, from pull request #456 + + * Fix ``bytearray('').replace('a', 'ab')``, issue #2324 diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,8 +29,8 @@ #define PY_VERSION "2.7.10" /* PyPy version as a string */ -#define PYPY_VERSION "5.3.1-alpha0" -#define PYPY_VERSION_NUM 0x05030100 +#define PYPY_VERSION "5.3.2-alpha0" +#define PYPY_VERSION_NUM 0x05030200 /* Defined to mean a PyPy where cpyext holds more regular references to PyObjects, e.g. staying alive as long as the internal PyPy object diff --git a/pypy/module/cpyext/pyfile.py b/pypy/module/cpyext/pyfile.py --- a/pypy/module/cpyext/pyfile.py +++ b/pypy/module/cpyext/pyfile.py @@ -55,6 +55,7 @@ if not PyFile_Check(space, w_p): raise oefmt(space.w_IOError, 'first argument must be an open file') assert isinstance(w_p, W_File) + w_p.stream.flush_buffers() try: fd = space.int_w(space.call_method(w_p, 'fileno')) mode = w_p.mode diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c --- a/pypy/module/cpyext/test/foo.c +++ b/pypy/module/cpyext/test/foo.c @@ -43,15 +43,6 @@ /* foo methods */ -static void -foo_dealloc(fooobject *foop) -{ - PyObject_Del(foop); -} - - -/* foo methods-as-attributes */ - static PyObject * foo_copy(fooobject *self) { @@ -195,7 +186,7 @@ sizeof(fooobject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ - (destructor)foo_dealloc, /*tp_dealloc*/ + 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -463,9 +454,9 @@ PyTypeObject InitErrType = { PyObject_HEAD_INIT(NULL) 0, - "foo.InitErr", - sizeof(PyObject), - 0, + "foo.InitErrType", + sizeof(PyObject),/*tp_basicsize*/ + 0, /*tp_itemsize*/ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ @@ -508,12 +499,12 @@ 0, /*tp_dictoffset*/ initerrtype_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ 0, /*tp_new*/ - 0, /*tp_free Low-level free-memory routine */ - 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ 0, /*tp_bases*/ - 0, /*tp_mro method resolution order */ + 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0 /*tp_weaklist*/ diff --git a/pypy/module/cpyext/test/test_pyfile.py b/pypy/module/cpyext/test/test_pyfile.py --- a/pypy/module/cpyext/test/test_pyfile.py +++ b/pypy/module/cpyext/test/test_pyfile.py @@ -1,5 +1,7 @@ +from pypy.conftest import option from pypy.module.cpyext.api import fopen, fclose, fwrite from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase from pypy.module.cpyext.object import Py_PRINT_RAW from rpython.rtyper.lltypesystem import rffi, lltype from rpython.tool.udir import udir @@ -111,3 +113,34 @@ out, err = capfd.readouterr() out = out.replace('\r\n', '\n') assert out == " 1 23\n" + + +class AppTestPyFile(AppTestCpythonExtensionBase): + + def setup_class(cls): + from rpython.tool.udir import udir + if option.runappdirect: + cls.w_udir = str(udir) + else: + cls.w_udir = cls.space.wrap(str(udir)) + + def test_file_tell(self): + module = self.import_extension('foo', [ + ("get_c_tell", "METH_O", + """ + FILE * fp = PyFile_AsFile(args); + if (fp == NULL) + return PyLong_FromLong(0); + return PyLong_FromLong(ftell(fp)); + """), + ]) + filename = self.udir + "/_test_file" + with open(filename, 'w') as fid: + fid.write('3' * 122) + with open(filename, 'r') as fid: + s = fid.read(80) + t_py = fid.tell() + assert t_py == 80 + t_c = module.get_c_tell(fid) + assert t_c == t_py + diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -142,6 +142,7 @@ ref = rffi.cast(PyTupleObject, ref) size = ref.c_ob_size if index < 0 or index >= size: + decref(space, py_obj) raise oefmt(space.w_IndexError, "tuple assignment index out of range") old_ref = ref.c_ob_item[index] ref.c_ob_item[index] = py_obj # consumes a reference diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -163,14 +163,10 @@ guard_not_invalidated(descr=...) i32 = float_ne(f31, 0.000000) guard_true(i32, descr=...) - i34 = getarrayitem_raw_i(#, #, descr=<ArrayU 1>) # XXX what are these? - guard_value(i34, #, descr=...) # XXX don't appear in - i35 = getarrayitem_raw_i(#, #, descr=<ArrayU 1>) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, 8) i38 = int_ge(i36, i30) guard_false(i38, descr=...) - guard_value(i35, #, descr=...) # XXX jump(..., descr=...) """) diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (5, 3, 1, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (5, 3, 2, "alpha", 0) #XXX # sync patchlevel.h import pypy diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -17,6 +17,7 @@ from pypy.objspace.std.unicodeobject import ( decode_object, unicode_from_encoded_object, unicode_from_string, getdefaultencoding) +from pypy.objspace.std.util import IDTAG_SPECIAL, IDTAG_SHIFT class W_AbstractBytesObject(W_Root): @@ -29,12 +30,26 @@ return True if self.user_overridden_class or w_other.user_overridden_class: return False - return space.str_w(self) is space.str_w(w_other) + s1 = space.str_w(self) + s2 = space.str_w(w_other) + if len(s2) > 1: + return s1 is s2 + else: # strings of len <= 1 are unique-ified + return s1 == s2 def immutable_unique_id(self, space): if self.user_overridden_class: return None - return space.wrap(compute_unique_id(space.str_w(self))) + s = space.str_w(self) + if len(s) > 1: + uid = compute_unique_id(s) + else: # strings of len <= 1 are unique-ified + if len(s) == 1: + base = ord(s[0]) # base values 0-255 + else: + base = 256 # empty string: base value 256 + uid = (base << IDTAG_SHIFT) | IDTAG_SPECIAL + return space.wrap(uid) def unicode_w(self, space): # Use the default encoding. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -6,6 +6,7 @@ from pypy.objspace.std.bytesobject import W_BytesObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import IDTAG_SPECIAL, IDTAG_SHIFT from rpython.rlib.objectmodel import r_dict from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash @@ -575,6 +576,23 @@ class W_FrozensetObject(W_BaseSetObject): hash = 0 + def is_w(self, space, w_other): + if not isinstance(w_other, W_FrozensetObject): + return False + if self is w_other: + return True + if self.user_overridden_class or w_other.user_overridden_class: + return False + # empty frozensets are unique-ified + return 0 == w_other.length() == self.length() + + def immutable_unique_id(self, space): + if self.user_overridden_class or self.length() > 0: + return None + # empty frozenset: base value 259 + uid = (259 << IDTAG_SHIFT) | IDTAG_SPECIAL + return space.wrap(uid) + def _newobj(self, space, w_iterable): """Make a new frozenset by taking ownership of 'w_iterable'.""" if type(self) is W_FrozensetObject: diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -162,7 +162,8 @@ buffer = _get_buffer(space, w_sub) res = count(value, buffer, start, end) - return space.wrap(max(res, 0)) + assert res >= 0 + return space.wrap(res) def descr_decode(self, space, w_encoding=None, w_errors=None): from pypy.objspace.std.unicodeobject import ( diff --git a/pypy/objspace/std/test/test_bytearrayobject.py b/pypy/objspace/std/test/test_bytearrayobject.py --- a/pypy/objspace/std/test/test_bytearrayobject.py +++ b/pypy/objspace/std/test/test_bytearrayobject.py @@ -211,6 +211,7 @@ check(bytearray('abc').replace('b', bytearray('d')), 'adc') check(bytearray('abc').replace('b', 'd'), 'adc') + check(bytearray('').replace('a', 'ab'), '') check(bytearray('abc').upper(), 'ABC') check(bytearray('ABC').lower(), 'abc') diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py --- a/pypy/objspace/std/test/test_obj.py +++ b/pypy/objspace/std/test/test_obj.py @@ -186,17 +186,36 @@ def test_id_on_strs(self): if self.appdirect: skip("cannot run this test as apptest") - u = u"a" - assert id(self.unwrap_wrap_unicode(u)) == id(u) - s = "a" - assert id(self.unwrap_wrap_str(s)) == id(s) + for u in [u"", u"a", u"aa"]: + assert id(self.unwrap_wrap_unicode(u)) == id(u) + s = str(u) + assert id(self.unwrap_wrap_str(s)) == id(s) + # + assert id('') == (256 << 4) | 11 # always + assert id(u'') == (257 << 4) | 11 + assert id('a') == (ord('a') << 4) | 11 + assert id(u'\u1234') == ((~0x1234) << 4) | 11 + + def test_id_of_tuples(self): + l = [] + x = (l,) + assert id(x) != id((l,)) # no caching at all + if self.appdirect: + skip("cannot run this test as apptest") + assert id(()) == (258 << 4) | 11 # always + + def test_id_of_frozensets(self): + x = frozenset([4]) + assert id(x) != id(frozenset([4])) # no caching at all + if self.appdirect: + skip("cannot run this test as apptest") + assert id(frozenset()) == (259 << 4) | 11 # always + assert id(frozenset([])) == (259 << 4) | 11 # always def test_identity_vs_id_primitives(self): - if self.cpython_apptest: - skip("cpython behaves differently") import sys - l = range(-10, 10) - for i in range(10): + l = range(-10, 10, 2) + for i in [0, 1, 3]: l.append(float(i)) l.append(i + 0.1) l.append(long(i)) @@ -206,18 +225,15 @@ l.append(i - 1j) l.append(1 + i * 1j) l.append(1 - i * 1j) - s = str(i) - l.append(s) - u = unicode(s) - l.append(u) + l.append((i,)) + l.append(frozenset([i])) l.append(-0.0) l.append(None) l.append(True) l.append(False) - s = "s" - l.append(s) - s = u"s" - l.append(s) + l.append(()) + l.append(tuple([])) + l.append(frozenset()) for i, a in enumerate(l): for b in l[i:]: @@ -228,21 +244,18 @@ def test_identity_vs_id_str(self): if self.appdirect: skip("cannot run this test as apptest") - import sys - l = range(-10, 10) - for i in range(10): - s = str(i) + l = [] + def add(s, u): l.append(s) l.append(self.unwrap_wrap_str(s)) - u = unicode(s) + l.append(s[:1] + s[1:]) l.append(u) l.append(self.unwrap_wrap_unicode(u)) - s = "s" - l.append(s) - l.append(self.unwrap_wrap_str(s)) - s = u"s" - l.append(s) - l.append(self.unwrap_wrap_unicode(s)) + l.append(u[:1] + u[1:]) + for i in range(3, 18): + add(str(i), unicode(i)) + add("s", u"s") + add("", u"") for i, a in enumerate(l): for b in l[i:]: diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -9,7 +9,7 @@ from pypy.interpreter.typedef import TypeDef from pypy.objspace.std.sliceobject import (W_SliceObject, unwrap_start_stop, normalize_simple_slice) -from pypy.objspace.std.util import negate +from pypy.objspace.std.util import negate, IDTAG_SPECIAL, IDTAG_SHIFT from rpython.rlib import jit from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask @@ -38,6 +38,23 @@ class W_AbstractTupleObject(W_Root): __slots__ = () + def is_w(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return False + if self is w_other: + return True + if self.user_overridden_class or w_other.user_overridden_class: + return False + # empty tuples are unique-ified + return 0 == w_other.length() == self.length() + + def immutable_unique_id(self, space): + if self.user_overridden_class or self.length() > 0: + return None + # empty tuple: base value 258 + uid = (258 << IDTAG_SHIFT) | IDTAG_SPECIAL + return space.wrap(uid) + def __repr__(self): """representation for debugging purposes""" reprlist = [repr(w_item) for w_item in self.tolist()] diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -18,6 +18,7 @@ from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.formatting import mod_format from pypy.objspace.std.stringmethods import StringMethods +from pypy.objspace.std.util import IDTAG_SPECIAL, IDTAG_SHIFT __all__ = ['W_UnicodeObject', 'wrapunicode', 'plain_str2unicode', 'encode_object', 'decode_object', 'unicode_from_object', @@ -52,12 +53,26 @@ return True if self.user_overridden_class or w_other.user_overridden_class: return False - return space.unicode_w(self) is space.unicode_w(w_other) + s1 = space.unicode_w(self) + s2 = space.unicode_w(w_other) + if len(s2) > 1: + return s1 is s2 + else: # strings of len <= 1 are unique-ified + return s1 == s2 def immutable_unique_id(self, space): if self.user_overridden_class: return None - return space.wrap(compute_unique_id(space.unicode_w(self))) + s = space.unicode_w(self) + if len(s) > 1: + uid = compute_unique_id(s) + else: # strings of len <= 1 are unique-ified + if len(s) == 1: + base = ~ord(s[0]) # negative base values + else: + base = 257 # empty unicode string: base value 257 + uid = (base << IDTAG_SHIFT) | IDTAG_SPECIAL + return space.wrap(uid) def str_w(self, space): return space.str_w(space.str(self)) diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py --- a/pypy/objspace/std/util.py +++ b/pypy/objspace/std/util.py @@ -9,6 +9,12 @@ IDTAG_FLOAT = 5 IDTAG_COMPLEX = 7 IDTAG_METHOD = 9 +IDTAG_SPECIAL = 11 # -1 - (-maxunicode-1): unichar + # 0 - 255: char + # 256: empty string + # 257: empty unicode + # 258: empty tuple + # 259: empty frozenset CMP_OPS = dict(lt='<', le='<=', eq='==', ne='!=', gt='>', ge='>=') BINARY_BITWISE_OPS = {'and': '&', 'lshift': '<<', 'or': '|', 'rshift': '>>', diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh --- a/pypy/tool/release/repackage.sh +++ b/pypy/tool/release/repackage.sh @@ -1,9 +1,9 @@ # Edit these appropriately before running this script maj=5 min=3 -rev=0 +rev=1 branchname=release-$maj.x # ==OR== release-$maj.$min.x -tagname=release-pypy2.7-v$maj.$min # ==OR== release-$maj.$min +tagname=release-pypy2.7-v$maj.$min.$rev # ==OR== release-$maj.$min echo checking hg log -r $branchname hg log -r $branchname || exit 1 diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -2,7 +2,7 @@ import py from rpython.jit.metainterp.optimizeopt.virtualstate import VirtualStateInfo,\ VStructStateInfo, LEVEL_CONSTANT,\ - VArrayStateInfo, NotVirtualStateInfo, VirtualState,\ + VArrayStateInfo, not_virtual, VirtualState,\ GenerateGuardState, VirtualStatesCantMatch, VArrayStructStateInfo from rpython.jit.metainterp.history import ConstInt, ConstPtr, TargetToken from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef,\ @@ -31,10 +31,10 @@ def setup_class(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - self.knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + self.knownclass_info = not_virtual(self.cpu, 'r', value) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) value = info.InstancePtrInfo(None, classbox) - self.knownclass_info2 = NotVirtualStateInfo(self.cpu, 'r', value) + self.knownclass_info2 = not_virtual(self.cpu, 'r', value) def guards(self, info1, info2, box, runtime_box, expected, inputargs=None): if inputargs is None: @@ -80,7 +80,7 @@ def test_make_inputargs(self): optimizer = FakeOptimizer(self.cpu) args = [InputArgInt()] - info0 = NotVirtualStateInfo(self.cpu, args[0].type, None) + info0 = not_virtual(self.cpu, args[0].type, None) vs = VirtualState([info0]) assert vs.make_inputargs(args, optimizer) == args info0.level = LEVEL_CONSTANT @@ -108,8 +108,8 @@ assert info1 in state.bad and info2 in state.bad for BoxType in (InputArgInt, InputArgFloat, InputArgRef): - info1 = NotVirtualStateInfo(self.cpu, BoxType.type, None) - info2 = NotVirtualStateInfo(self.cpu, BoxType.type, None) + info1 = not_virtual(self.cpu, BoxType.type, None) + info2 = not_virtual(self.cpu, BoxType.type, None) postest(info1, info2) info1, info2 = VArrayStateInfo(42), VArrayStateInfo(42) @@ -126,9 +126,9 @@ def test_NotVirtualStateInfo_generalization(self): def isgeneral(tp1, info1, tp2, info2): - info1 = NotVirtualStateInfo(self.cpu, tp1, info1) + info1 = not_virtual(self.cpu, tp1, info1) info1.position = 0 - info2 = NotVirtualStateInfo(self.cpu, tp2, info2) + info2 = not_virtual(self.cpu, tp2, info2) info2.position = 0 return VirtualState([info1]).generalization_of(VirtualState([info2]), FakeOptimizer(self.cpu)) @@ -166,8 +166,8 @@ assert not isgeneral('r', value1, 'r', value2) def test_field_matching_generalization(self): - const1 = NotVirtualStateInfo(self.cpu, 'i', ConstIntBound(1)) - const2 = NotVirtualStateInfo(self.cpu, 'i', ConstIntBound(2)) + const1 = not_virtual(self.cpu, 'i', ConstIntBound(1)) + const2 = not_virtual(self.cpu, 'i', ConstIntBound(2)) const1.position = const2.position = 1 self.check_invalid(const1, const2) self.check_invalid(const2, const1) @@ -192,16 +192,16 @@ def test_known_class_generalization(self): knownclass1 = info.InstancePtrInfo(None, ConstPtr(self.myptr)) - info1 = NotVirtualStateInfo(self.cpu, 'r', knownclass1) + info1 = not_virtual(self.cpu, 'r', knownclass1) info1.position = 0 knownclass2 = info.InstancePtrInfo(None, ConstPtr(self.myptr)) - info2 = NotVirtualStateInfo(self.cpu, 'r', knownclass2) + info2 = not_virtual(self.cpu, 'r', knownclass2) info2.position = 0 self.check_no_guards(info1, info2) self.check_no_guards(info2, info1) knownclass3 = info.InstancePtrInfo(None, ConstPtr(self.myptr2)) - info3 = NotVirtualStateInfo(self.cpu, 'r', knownclass3) + info3 = not_virtual(self.cpu, 'r', knownclass3) info3.position = 0 self.check_invalid(info1, info3) self.check_invalid(info2, info3) @@ -222,26 +222,26 @@ #unknown_val = PtrOptValue(self.nodebox) #unknownnull_val = PtrOptValue(BoxPtr(self.nullptr)) opt = FakeOptimizer(self.cpu) - unknown_info = NotVirtualStateInfo(self.cpu, 'r', None) + unknown_info = not_virtual(self.cpu, 'r', None) - nonnull_info = NotVirtualStateInfo(self.cpu, 'r', info.NonNullPtrInfo()) + nonnull_info = not_virtual(self.cpu, 'r', info.NonNullPtrInfo()) classbox1 = self.cpu.ts.cls_of_box(ConstPtr(self.nodeaddr)) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', - info.InstancePtrInfo(None, classbox1)) + knownclass_info = not_virtual(self.cpu, 'r', + info.InstancePtrInfo(None, classbox1)) classbox2 = self.cpu.ts.cls_of_box(ConstPtr(self.node2addr)) - knownclass2_info = NotVirtualStateInfo(self.cpu, 'r', - info.InstancePtrInfo(None, classbox2)) + knownclass2_info = not_virtual(self.cpu, 'r', + info.InstancePtrInfo(None, classbox2)) - constant_info = NotVirtualStateInfo(self.cpu, 'i', - ConstIntBound(1)) - constant_ptr_info = NotVirtualStateInfo(self.cpu, 'r', + constant_info = not_virtual(self.cpu, 'i', + ConstIntBound(1)) + constant_ptr_info = not_virtual(self.cpu, 'r', info.ConstPtrInfo(ConstPtr(self.nodeaddr))) constclass_val = info.ConstPtrInfo(ConstPtr(self.nodeaddr)) - constclass_info = NotVirtualStateInfo(self.cpu, 'r', constclass_val) - constclass2_info = NotVirtualStateInfo(self.cpu, 'r', + constclass_info = not_virtual(self.cpu, 'r', constclass_val) + constclass2_info = not_virtual(self.cpu, 'r', info.ConstPtrInfo(ConstPtr(self.node2addr))) - constantnull_info = NotVirtualStateInfo(self.cpu, 'r', + constantnull_info = not_virtual(self.cpu, 'r', info.ConstPtrInfo(ConstPtr(self.nullptr))) # unknown unknown @@ -260,9 +260,10 @@ self.check_no_guards(unknown_info, knownclass_info) # unknown constant - self.check_no_guards(unknown_info, constant_info, + unknown_info_int = not_virtual(self.cpu, 'i', None) + self.check_no_guards(unknown_info_int, constant_info, ConstInt(1), ConstIntBound(1)) - self.check_no_guards(unknown_info, constant_info) + self.check_no_guards(unknown_info_int, constant_info) # nonnull unknown @@ -293,11 +294,11 @@ const_nonnull = ConstPtr(self.nodeaddr) const_nonnull2 = ConstPtr(self.node2addr) const_null = ConstPtr(lltype.nullptr(llmemory.GCREF.TO)) - self.check_no_guards(nonnull_info, constant_info, const_nonnull, + self.check_no_guards(nonnull_info, constant_ptr_info, const_nonnull, info.ConstPtrInfo(const_nonnull)) self.check_invalid(nonnull_info, constantnull_info, const_null, info.ConstPtrInfo(const_null)) - self.check_no_guards(nonnull_info, constant_info) + self.check_no_guards(nonnull_info, constant_ptr_info) self.check_invalid(nonnull_info, constantnull_info) @@ -392,8 +393,8 @@ value1 = IntUnbounded() value1.make_ge(IntBound(0, 10)) value1.make_le(IntBound(20, 30)) - info1 = NotVirtualStateInfo(self.cpu, 'i', value1) - info2 = NotVirtualStateInfo(self.cpu, 'i', IntUnbounded()) + info1 = not_virtual(self.cpu, 'i', value1) + info2 = not_virtual(self.cpu, 'i', IntUnbounded()) expected = """ [i0] i1 = int_ge(i0, 0) @@ -408,18 +409,18 @@ value1 = IntUnbounded() value1.make_ge(IntBound(0, 10)) value1.make_le(IntBound(20, 30)) - info1 = NotVirtualStateInfo(self.cpu, 'i', value1) - info2 = NotVirtualStateInfo(self.cpu, 'i', ConstIntBound(10000)) + info1 = not_virtual(self.cpu, 'i', value1) + info2 = not_virtual(self.cpu, 'i', ConstIntBound(10000)) self.check_invalid(info1, info2) - info1 = NotVirtualStateInfo(self.cpu, 'i', value1) - info2 = NotVirtualStateInfo(self.cpu, 'i', ConstIntBound(11)) + info1 = not_virtual(self.cpu, 'i', value1) + info2 = not_virtual(self.cpu, 'i', ConstIntBound(11)) self.check_no_guards(info1, info2) def test_known_class(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value1 = info.InstancePtrInfo(None, classbox) - info1 = NotVirtualStateInfo(self.cpu, 'r', value1) - info2 = NotVirtualStateInfo(self.cpu, 'r', None) + info1 = not_virtual(self.cpu, 'r', value1) + info2 = not_virtual(self.cpu, 'r', None) expected = """ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] @@ -456,18 +457,18 @@ def test_equal_inputargs(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) vstate1 = VirtualState([knownclass_info, knownclass_info]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) - unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', None) + unknown_info1 = not_virtual(self.cpu, 'r', None) vstate2 = VirtualState([unknown_info1, unknown_info1]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) assert vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) - unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', None) - unknown_info2 = NotVirtualStateInfo(self.cpu, 'r', None) + unknown_info1 = not_virtual(self.cpu, 'r', None) + unknown_info2 = not_virtual(self.cpu, 'r', None) vstate3 = VirtualState([unknown_info1, unknown_info2]) assert vstate3.generalization_of(vstate2, FakeOptimizer(self.cpu)) assert vstate3.generalization_of(vstate1, FakeOptimizer(self.cpu)) @@ -494,9 +495,9 @@ def test_generate_guards_on_virtual_fields_matches_array(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) innervalue1 = info.InstancePtrInfo(None, classbox) - innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) + innerinfo1 = not_virtual(self.cpu, 'r', innervalue1) innerinfo1.position = 1 - innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) + innerinfo2 = not_virtual(self.cpu, 'r', None) innerinfo2.position = 1 descr = ArrayDescr(lltype.GcArray(llmemory.GCREF), self.cpu) @@ -524,9 +525,9 @@ def test_generate_guards_on_virtual_fields_matches_instance(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) innervalue1 = info.InstancePtrInfo(None, classbox) - innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) + innerinfo1 = not_virtual(self.cpu, 'r', innervalue1) innerinfo1.position = 1 - innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) + innerinfo2 = not_virtual(self.cpu, 'r', None) innerinfo2.position = 1 info1 = VirtualStateInfo(ConstInt(42), [self.nextdescr]) @@ -552,9 +553,9 @@ def test_generate_guards_on_virtual_fields_matches_struct(self): constclassbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) innervalue1 = info.InstancePtrInfo(None, constclassbox) - innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) + innerinfo1 = not_virtual(self.cpu, 'r', innervalue1) innerinfo1.position = 1 - innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) + innerinfo2 = not_virtual(self.cpu, 'r', None) innerinfo2.position = 1 structdescr = self.nodesize @@ -583,9 +584,9 @@ def test_generate_guards_on_virtual_fields_matches_arraystruct(self): constclassbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) innervalue1 = info.InstancePtrInfo(None, constclassbox) - innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) + innerinfo1 = not_virtual(self.cpu, 'r', innervalue1) innerinfo1.position = 1 - innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) + innerinfo2 = not_virtual(self.cpu, 'r', None) innerinfo2.position = 1 NODE = lltype.Struct('NODE', ('x', llmemory.GCREF)) @@ -627,7 +628,7 @@ assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VirtualStateInfo(ConstInt(42), [1, 2]) - unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', + unknown_info1 = not_virtual(self.cpu, 'r', info.InstancePtrInfo()) info2.fieldstate = [unknown_info1, unknown_info1] vstate2 = VirtualState([info2]) @@ -636,9 +637,9 @@ assert vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) info3 = VirtualStateInfo(ConstInt(42), [1, 2]) - unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', + unknown_info1 = not_virtual(self.cpu, 'r', info.InstancePtrInfo()) - unknown_info2 = NotVirtualStateInfo(self.cpu, 'r', + unknown_info2 = not_virtual(self.cpu, 'r', info.InstancePtrInfo()) info3.fieldstate = [unknown_info1, unknown_info2] vstate3 = VirtualState([info3]) @@ -651,7 +652,7 @@ info1 = VirtualStateInfo(ConstInt(42), [1, 2]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) @@ -659,7 +660,7 @@ info2 = VirtualStateInfo(ConstInt(42), [1, 2]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) @@ -671,7 +672,7 @@ info1 = VirtualStateInfo(ConstInt(42), [10, 20]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) @@ -679,7 +680,7 @@ info2 = VirtualStateInfo(ConstInt(42), [1, 2]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) @@ -691,7 +692,7 @@ info1 = VirtualStateInfo(ConstInt(42), [1, 2]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) @@ -699,24 +700,24 @@ info2 = VirtualStateInfo(ConstInt(7), [1, 2]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) - + def test_nonvirtual_is_not_virtual(self): info1 = VirtualStateInfo(ConstInt(42), [1, 2]) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) - info2 = NotVirtualStateInfo(self.cpu, 'r', value) + info2 = not_virtual(self.cpu, 'r', value) vstate2 = VirtualState([info2]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) @@ -727,7 +728,7 @@ info1 = VArrayStateInfo(42) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) @@ -735,7 +736,7 @@ info2 = VArrayStateInfo(42) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) @@ -747,7 +748,7 @@ info1 = VArrayStateInfo(42) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) @@ -755,7 +756,7 @@ info2 = VArrayStateInfo(42) classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) value = info.InstancePtrInfo(None, classbox) - knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + knownclass_info = not_virtual(self.cpu, 'r', value) info2.fieldstate = [knownclass_info] vstate2 = VirtualState([info2]) assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) @@ -793,7 +794,7 @@ def test_crash_varay_clear(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) innervalue1 = info.InstancePtrInfo(None, classbox) - innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) + innerinfo1 = not_virtual(self.cpu, 'r', innervalue1) innerinfo1.position = 1 innerinfo1.position_in_notvirtuals = 0 diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -350,40 +350,23 @@ def debug_header(self, indent): debug_print(indent + 'VArrayStructStateInfo(%d):' % self.position) + +def not_virtual(cpu, type, info): + if type == 'i': + return NotVirtualStateInfoInt(cpu, type, info) + if type == 'r': + return NotVirtualStateInfoPtr(cpu, type, info) + return NotVirtualStateInfo(cpu, type, info) + + class NotVirtualStateInfo(AbstractVirtualStateInfo): - lenbound = None - intbound = None level = LEVEL_UNKNOWN constbox = None - known_class = None - + def __init__(self, cpu, type, info): if info and info.is_constant(): self.level = LEVEL_CONSTANT self.constbox = info.getconst() - if type == 'r': - self.known_class = info.get_known_class(cpu) - elif type == 'i': - self.intbound = info - elif type == 'r': - if info: - self.known_class = info.get_known_class(cpu) - if self.known_class: - self.level = LEVEL_KNOWNCLASS - elif info.is_nonnull(): - self.level = LEVEL_NONNULL - self.lenbound = info.getlenbound(None) - elif type == 'i': - if isinstance(info, IntBound): - if info.lower < MININT / 2: - info.lower = MININT - if info.upper > MAXINT / 2: - info.upper = MAXINT - self.intbound = info - elif type == 'f': - if info and info.is_constant(): - self.level = LEVEL_CONSTANT - self.constbox = info.getconst() def is_const(self): return self.constbox is not None @@ -394,84 +377,15 @@ def _generate_guards(self, other, box, runtime_box, state): # XXX This will always retrace instead of forcing anything which # might be what we want sometimes? - if not isinstance(other, NotVirtualStateInfo): - raise VirtualStatesCantMatch( - 'The VirtualStates does not match as a ' + - 'virtual appears where a pointer is needed ' + - 'and it is too late to force it.') - - extra_guards = state.extra_guards - cpu = state.cpu - if self.lenbound: - if other.lenbound is None: - other_bound = IntLowerBound(0) - else: - other_bound = other.lenbound - if not self.lenbound.contains_bound(other_bound): - raise VirtualStatesCantMatch("length bound does not match") - if self.level == LEVEL_UNKNOWN: - # confusingly enough, this is done also for pointers - # which have the full range as the "bound", so it always works - return self._generate_guards_intbounds(other, box, runtime_box, - extra_guards, - state.optimizer) - - # the following conditions often peek into the runtime value that the - # box had when tracing. This value is only used as an educated guess. - # It is used here to choose between either emitting a guard and jumping - # to an existing compiled loop or retracing the loop. Both alternatives - # will always generate correct behaviour, but performance will differ. - elif self.level == LEVEL_NONNULL: - if other.level == LEVEL_UNKNOWN: - if runtime_box is not None and runtime_box.nonnull(): - op = ResOperation(rop.GUARD_NONNULL, [box]) - extra_guards.append(op) - return - else: - raise VirtualStatesCantMatch("other not known to be nonnull") - elif other.level == LEVEL_NONNULL: - return - elif other.level == LEVEL_KNOWNCLASS: - return # implies nonnull - else: - assert other.level == LEVEL_CONSTANT - assert other.constbox - if not other.constbox.nonnull(): - raise VirtualStatesCantMatch("constant is null") - return - - elif self.level == LEVEL_KNOWNCLASS: - if other.level == LEVEL_UNKNOWN: - if (runtime_box and runtime_box.nonnull() and - self.known_class.same_constant(cpu.ts.cls_of_box(runtime_box))): - op = ResOperation(rop.GUARD_NONNULL_CLASS, [box, self.known_class]) - extra_guards.append(op) - return - else: - raise VirtualStatesCantMatch("other's class is unknown") - elif other.level == LEVEL_NONNULL: - if (runtime_box and self.known_class.same_constant( - cpu.ts.cls_of_box(runtime_box))): - op = ResOperation(rop.GUARD_CLASS, [box, self.known_class]) - extra_guards.append(op) - return - else: - raise VirtualStatesCantMatch("other's class is unknown") - elif other.level == LEVEL_KNOWNCLASS: - if self.known_class.same_constant(other.known_class): - return - raise VirtualStatesCantMatch("classes don't match") - else: - assert other.level == LEVEL_CONSTANT - if (other.constbox.nonnull() and - self.known_class.same_constant(cpu.ts.cls_of_box(other.constbox))): - return - else: - raise VirtualStatesCantMatch("classes don't match") - + return self._generate_guards_unkown(other, box, runtime_box, + extra_guards, + state) else: + if not isinstance(other, NotVirtualStateInfo): + raise VirtualStatesCantMatch( + 'comparing a constant against something that is a virtual') assert self.level == LEVEL_CONSTANT if other.level == LEVEL_CONSTANT: if self.constbox.same_constant(other.constbox): @@ -485,19 +399,9 @@ raise VirtualStatesCantMatch("other not constant") assert 0, "unreachable" - def _generate_guards_intbounds(self, other, box, runtime_box, extra_guards, - optimizer): - if self.intbound is None: - return - if self.intbound.contains_bound(other.intbound): - return - if (runtime_box is not None and - self.intbound.contains(runtime_box.getint())): - # this may generate a few more guards than needed, but they are - # optimized away when emitting them - self.intbound.make_guards(box, extra_guards, optimizer) - return - raise VirtualStatesCantMatch("intbounds don't match") + def _generate_guards_unkown(self, other, box, runtime_box, extra_guards, + state): + return def enum_forced_boxes(self, boxes, box, optimizer, force_boxes=False): if self.level == LEVEL_CONSTANT: @@ -553,8 +457,145 @@ if self.lenbound: lb = ', ' + self.lenbound.bound.__repr__() - debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position + - ', ' + l + ', ' + self.intbound.__repr__() + lb + ')') + result = indent + mark + 'NotVirtualStateInfo(%d' % self.position + ', ' + l + extra = self._extra_repr() + if extra: + result += ', ' + extra + result += lb + ')' + debug_print(result) + +class NotVirtualStateInfoInt(NotVirtualStateInfo): + intbound = None + + def __init__(self, cpu, type, info): + NotVirtualStateInfo.__init__(self, cpu, type, info) + assert type == 'i' + if isinstance(info, IntBound): + if info.lower < MININT / 2: + info.lower = MININT + if info.upper > MAXINT / 2: + info.upper = MAXINT + self.intbound = info + + def _generate_guards_unkown(self, other, box, runtime_box, extra_guards, + optimizer): + other_intbound = None + if isinstance(other, NotVirtualStateInfoInt): + other_intbound = other.intbound + if self.intbound is None: + return + if self.intbound.contains_bound(other_intbound): + return + if (runtime_box is not None and + self.intbound.contains(runtime_box.getint())): + # this may generate a few more guards than needed, but they are + # optimized away when emitting them + self.intbound.make_guards(box, extra_guards, optimizer) + return + raise VirtualStatesCantMatch("intbounds don't match") + + def _extra_repr(self): + return self.intbound.__repr__() + + +class NotVirtualStateInfoPtr(NotVirtualStateInfo): + lenbound = None + known_class = None + + def __init__(self, cpu, type, info): + if info: + self.known_class = info.get_known_class(cpu) + if self.known_class: + self.level = LEVEL_KNOWNCLASS + elif info.is_nonnull(): + self.level = LEVEL_NONNULL + self.lenbound = info.getlenbound(None) + # might set it to LEVEL_CONSTANT + NotVirtualStateInfo.__init__(self, cpu, type, info) + + def _generate_guards(self, other, box, runtime_box, state): + if not isinstance(other, NotVirtualStateInfoPtr): + raise VirtualStatesCantMatch( + 'The VirtualStates does not match as a ' + + 'virtual appears where a pointer is needed ' + + 'and it is too late to force it.') + extra_guards = state.extra_guards + if self.lenbound: + if other.lenbound is None: + other_bound = IntLowerBound(0) + else: + other_bound = other.lenbound + if not self.lenbound.contains_bound(other_bound): + raise VirtualStatesCantMatch("length bound does not match") + if self.level == LEVEL_NONNULL: + return self._generate_guards_nonnull(other, box, runtime_box, + extra_guards, + state) + elif self.level == LEVEL_KNOWNCLASS: + return self._generate_guards_knownclass(other, box, runtime_box, + extra_guards, + state) + return NotVirtualStateInfo._generate_guards(self, other, box, + runtime_box, state) + + + # the following methods often peek into the runtime value that the + # box had when tracing. This value is only used as an educated guess. + # It is used here to choose between either emitting a guard and jumping + # to an existing compiled loop or retracing the loop. Both alternatives + # will always generate correct behaviour, but performance will differ. + + def _generate_guards_nonnull(self, other, box, runtime_box, extra_guards, + state): + if not isinstance(other, NotVirtualStateInfoPtr): + raise VirtualStatesCantMatch('trying to match ptr with non-ptr??!') + if other.level == LEVEL_UNKNOWN: + if runtime_box is not None and runtime_box.nonnull(): + op = ResOperation(rop.GUARD_NONNULL, [box]) + extra_guards.append(op) + return + else: + raise VirtualStatesCantMatch("other not known to be nonnull") + elif other.level == LEVEL_NONNULL: + pass + elif other.level == LEVEL_KNOWNCLASS: + pass # implies nonnull + else: + assert other.level == LEVEL_CONSTANT + assert other.constbox + if not other.constbox.nonnull(): + raise VirtualStatesCantMatch("constant is null") + + def _generate_guards_knownclass(self, other, box, runtime_box, extra_guards, + state): + cpu = state.cpu + if not isinstance(other, NotVirtualStateInfoPtr): + raise VirtualStatesCantMatch('trying to match ptr with non-ptr??!') + if other.level == LEVEL_UNKNOWN: + if (runtime_box and runtime_box.nonnull() and + self.known_class.same_constant(cpu.ts.cls_of_box(runtime_box))): + op = ResOperation(rop.GUARD_NONNULL_CLASS, [box, self.known_class]) + extra_guards.append(op) + else: + raise VirtualStatesCantMatch("other's class is unknown") + elif other.level == LEVEL_NONNULL: + if (runtime_box and self.known_class.same_constant( + cpu.ts.cls_of_box(runtime_box))): + op = ResOperation(rop.GUARD_CLASS, [box, self.known_class]) + extra_guards.append(op) + else: + raise VirtualStatesCantMatch("other's class is unknown") + elif other.level == LEVEL_KNOWNCLASS: + if self.known_class.same_constant(other.known_class): + return + raise VirtualStatesCantMatch("classes don't match") + else: + assert other.level == LEVEL_CONSTANT + if (other.constbox.nonnull() and + self.known_class.same_constant(cpu.ts.cls_of_box(other.constbox))): + pass + else: + raise VirtualStatesCantMatch("classes don't match") class VirtualState(object): @@ -678,8 +719,8 @@ return VirtualState(state) def visit_not_virtual(self, box): - return NotVirtualStateInfo(self.optimizer.cpu, box.type, - self.optimizer.getinfo(box)) + return not_virtual(self.optimizer.cpu, box.type, + self.optimizer.getinfo(box)) def visit_virtual(self, descr, fielddescrs): known_class = ConstInt(descr.get_vtable()) diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py --- a/rpython/rlib/rstring.py +++ b/rpython/rlib/rstring.py @@ -291,6 +291,7 @@ return _search(value, other, start, end, SEARCH_COUNT) # -------------- substring searching helper ---------------- +# XXX a lot of code duplication with lltypesystem.rstr :-( SEARCH_COUNT = 0 SEARCH_FIND = 1 @@ -309,6 +310,8 @@ if end > len(value): end = len(value) if start > end: + if mode == SEARCH_COUNT: + return 0 return -1 count = 0 @@ -326,6 +329,8 @@ w = n - m if w < 0: + if mode == SEARCH_COUNT: + return 0 return -1 mlast = m - 1 @@ -570,18 +575,20 @@ class ByteListBuilder(object): def __init__(self, init_size=INIT_SIZE): + assert init_size >= 0 self.l = newlist_hint(init_size) @specialize.argtype(1) def append(self, s): + l = self.l for c in s: - self.l.append(c) + l.append(c) @specialize.argtype(1) def append_slice(self, s, start, end): - assert 0 <= start <= end <= len(s) - for c in s[start:end]: - self.l.append(c) + l = self.l + for i in xrange(start, end): + l.append(s[i]) def append_multiple_char(self, c, times): assert isinstance(c, str) @@ -589,8 +596,9 @@ def append_charpsize(self, s, size): assert size >= 0 + l = self.l for i in xrange(size): - self.l.append(s[i]) + l.append(s[i]) def build(self): return self.l diff --git a/rpython/rlib/test/test_rstring.py b/rpython/rlib/test/test_rstring.py --- a/rpython/rlib/test/test_rstring.py +++ b/rpython/rlib/test/test_rstring.py @@ -231,6 +231,10 @@ check_search(count, 'one two three', 'e', 0, 1, res=0) check_search(count, 'one two three', '', 0, 13, res=14) + check_search(count, '', 'ab', 0, 0, res=0) + check_search(count, 'a', 'ab', 0, 1, res=0) + check_search(count, 'ac', 'ab', 0, 2, res=0) + class TestTranslates(BaseRtypingTest): def test_split_rsplit(self): diff --git a/rpython/rtyper/test/test_rstr.py b/rpython/rtyper/test/test_rstr.py --- a/rpython/rtyper/test/test_rstr.py +++ b/rpython/rtyper/test/test_rstr.py @@ -972,6 +972,13 @@ s.count(s, -10) py.test.raises(AnnotatorError, self.interpret, f, ()) + def test_count_in_empty_string(self): + const = self.const + def fn(): + return const('').count(const('ab')) + res = self.interpret(fn, []) + assert res == 0 + def test_getitem_exc(self): const = self.const def f(x): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit