[pypy-commit] pypy default: merged from pypy a3d4b51ec806
Stefano Parmesan
noreply at buildbot.pypy.org
Wed Feb 8 10:58:22 CET 2012
Author: Stefano Parmesan <stefanop at ahref.eu>
Branch:
Changeset: r52217:4fd8ce7642df
Date: 2012-02-08 09:45 +0100
http://bitbucket.org/pypy/pypy/changeset/4fd8ce7642df/
Log: merged from pypy a3d4b51ec806
diff --git a/py/_io/terminalwriter.py b/py/_io/terminalwriter.py
--- a/py/_io/terminalwriter.py
+++ b/py/_io/terminalwriter.py
@@ -271,16 +271,24 @@
('srWindow', SMALL_RECT),
('dwMaximumWindowSize', COORD)]
+ _GetStdHandle = ctypes.windll.kernel32.GetStdHandle
+ _GetStdHandle.argtypes = [wintypes.DWORD]
+ _GetStdHandle.restype = wintypes.HANDLE
def GetStdHandle(kind):
- return ctypes.windll.kernel32.GetStdHandle(kind)
+ return _GetStdHandle(kind)
- SetConsoleTextAttribute = \
- ctypes.windll.kernel32.SetConsoleTextAttribute
-
+ SetConsoleTextAttribute = ctypes.windll.kernel32.SetConsoleTextAttribute
+ SetConsoleTextAttribute.argtypes = [wintypes.HANDLE, wintypes.WORD]
+ SetConsoleTextAttribute.restype = wintypes.BOOL
+
+ _GetConsoleScreenBufferInfo = \
+ ctypes.windll.kernel32.GetConsoleScreenBufferInfo
+ _GetConsoleScreenBufferInfo.argtypes = [wintypes.HANDLE,
+ ctypes.POINTER(CONSOLE_SCREEN_BUFFER_INFO)]
+ _GetConsoleScreenBufferInfo.restype = wintypes.BOOL
def GetConsoleInfo(handle):
info = CONSOLE_SCREEN_BUFFER_INFO()
- ctypes.windll.kernel32.GetConsoleScreenBufferInfo(\
- handle, ctypes.byref(info))
+ _GetConsoleScreenBufferInfo(handle, ctypes.byref(info))
return info
def _getdimensions():
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -93,6 +93,10 @@
# make input arguments and set their type
args_s = [self.typeannotation(t) for t in input_arg_types]
+ # XXX hack
+ annmodel.TLS.check_str_without_nul = (
+ self.translator.config.translation.check_str_without_nul)
+
flowgraph, inputcells = self.get_call_parameters(function, args_s, policy)
if not isinstance(flowgraph, FunctionGraph):
assert isinstance(flowgraph, annmodel.SomeObject)
diff --git a/pypy/annotation/binaryop.py b/pypy/annotation/binaryop.py
--- a/pypy/annotation/binaryop.py
+++ b/pypy/annotation/binaryop.py
@@ -434,11 +434,13 @@
class __extend__(pairtype(SomeString, SomeString)):
def union((str1, str2)):
- return SomeString(can_be_None=str1.can_be_None or str2.can_be_None)
+ can_be_None = str1.can_be_None or str2.can_be_None
+ no_nul = str1.no_nul and str2.no_nul
+ return SomeString(can_be_None=can_be_None, no_nul=no_nul)
def add((str1, str2)):
# propagate const-ness to help getattr(obj, 'prefix' + const_name)
- result = SomeString()
+ result = SomeString(no_nul=str1.no_nul and str2.no_nul)
if str1.is_immutable_constant() and str2.is_immutable_constant():
result.const = str1.const + str2.const
return result
@@ -475,7 +477,16 @@
raise NotImplementedError(
"string formatting mixing strings and unicode not supported")
getbookkeeper().count('strformat', str, s_tuple)
- return SomeString()
+ no_nul = str.no_nul
+ for s_item in s_tuple.items:
+ if isinstance(s_item, SomeFloat):
+ pass # or s_item is a subclass, like SomeInteger
+ elif isinstance(s_item, SomeString) and s_item.no_nul:
+ pass
+ else:
+ no_nul = False
+ break
+ return SomeString(no_nul=no_nul)
class __extend__(pairtype(SomeString, SomeObject)):
@@ -828,7 +839,7 @@
exec source.compile() in glob
_make_none_union('SomeInstance', 'classdef=obj.classdef, can_be_None=True')
-_make_none_union('SomeString', 'can_be_None=True')
+_make_none_union('SomeString', 'no_nul=obj.no_nul, can_be_None=True')
_make_none_union('SomeUnicodeString', 'can_be_None=True')
_make_none_union('SomeList', 'obj.listdef')
_make_none_union('SomeDict', 'obj.dictdef')
diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py
--- a/pypy/annotation/bookkeeper.py
+++ b/pypy/annotation/bookkeeper.py
@@ -342,10 +342,11 @@
else:
raise Exception("seeing a prebuilt long (value %s)" % hex(x))
elif issubclass(tp, str): # py.lib uses annotated str subclasses
+ no_nul = not '\x00' in x
if len(x) == 1:
- result = SomeChar()
+ result = SomeChar(no_nul=no_nul)
else:
- result = SomeString()
+ result = SomeString(no_nul=no_nul)
elif tp is unicode:
if len(x) == 1:
result = SomeUnicodeCodePoint()
diff --git a/pypy/annotation/listdef.py b/pypy/annotation/listdef.py
--- a/pypy/annotation/listdef.py
+++ b/pypy/annotation/listdef.py
@@ -86,18 +86,19 @@
read_locations = self.read_locations.copy()
other_read_locations = other.read_locations.copy()
self.read_locations.update(other.read_locations)
- self.patch() # which should patch all refs to 'other'
s_value = self.s_value
s_other_value = other.s_value
s_new_value = unionof(s_value, s_other_value)
+ if s_new_value != s_value:
+ if self.dont_change_any_more:
+ raise TooLateForChange
if isdegenerated(s_new_value):
if self.bookkeeper:
self.bookkeeper.ondegenerated(self, s_new_value)
elif other.bookkeeper:
other.bookkeeper.ondegenerated(other, s_new_value)
+ self.patch() # which should patch all refs to 'other'
if s_new_value != s_value:
- if self.dont_change_any_more:
- raise TooLateForChange
self.s_value = s_new_value
# reflow from reading points
for position_key in read_locations:
@@ -222,4 +223,5 @@
MOST_GENERAL_LISTDEF = ListDef(None, SomeObject())
-s_list_of_strings = SomeList(ListDef(None, SomeString(), resized = True))
+s_list_of_strings = SomeList(ListDef(None, SomeString(no_nul=True),
+ resized = True))
diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -39,7 +39,9 @@
DEBUG = False # set to False to disable recording of debugging information
class State(object):
- pass
+ # A global attribute :-( Patch it with 'True' to enable checking of
+ # the no_nul attribute...
+ check_str_without_nul = False
TLS = State()
class SomeObject(object):
@@ -225,43 +227,57 @@
def __init__(self):
pass
-class SomeString(SomeObject):
- "Stands for an object which is known to be a string."
- knowntype = str
+class SomeStringOrUnicode(SomeObject):
immutable = True
- def __init__(self, can_be_None=False):
- self.can_be_None = can_be_None
+ can_be_None=False
+ no_nul = False # No NUL character in the string.
+
+ def __init__(self, can_be_None=False, no_nul=False):
+ if can_be_None:
+ self.can_be_None = True
+ if no_nul:
+ self.no_nul = True
def can_be_none(self):
return self.can_be_None
+ def __eq__(self, other):
+ if self.__class__ is not other.__class__:
+ return False
+ d1 = self.__dict__
+ d2 = other.__dict__
+ if not TLS.check_str_without_nul:
+ d1 = d1.copy(); d1['no_nul'] = 0 # ignored
+ d2 = d2.copy(); d2['no_nul'] = 0 # ignored
+ return d1 == d2
+
+class SomeString(SomeStringOrUnicode):
+ "Stands for an object which is known to be a string."
+ knowntype = str
+
def nonnoneify(self):
- return SomeString(can_be_None=False)
+ return SomeString(can_be_None=False, no_nul=self.no_nul)
-class SomeUnicodeString(SomeObject):
+class SomeUnicodeString(SomeStringOrUnicode):
"Stands for an object which is known to be an unicode string"
knowntype = unicode
- immutable = True
- def __init__(self, can_be_None=False):
- self.can_be_None = can_be_None
-
- def can_be_none(self):
- return self.can_be_None
def nonnoneify(self):
- return SomeUnicodeString(can_be_None=False)
+ return SomeUnicodeString(can_be_None=False, no_nul=self.no_nul)
class SomeChar(SomeString):
"Stands for an object known to be a string of length 1."
can_be_None = False
- def __init__(self): # no 'can_be_None' argument here
- pass
+ def __init__(self, no_nul=False): # no 'can_be_None' argument here
+ if no_nul:
+ self.no_nul = True
class SomeUnicodeCodePoint(SomeUnicodeString):
"Stands for an object known to be a unicode codepoint."
can_be_None = False
- def __init__(self): # no 'can_be_None' argument here
- pass
+ def __init__(self, no_nul=False): # no 'can_be_None' argument here
+ if no_nul:
+ self.no_nul = True
SomeString.basestringclass = SomeString
SomeString.basecharclass = SomeChar
@@ -502,6 +518,7 @@
s_None = SomePBC([], can_be_None=True)
s_Bool = SomeBool()
s_ImpossibleValue = SomeImpossibleValue()
+s_Str0 = SomeString(no_nul=True)
# ____________________________________________________________
# weakrefs
@@ -716,8 +733,7 @@
def not_const(s_obj):
if s_obj.is_constant():
- new_s_obj = SomeObject()
- new_s_obj.__class__ = s_obj.__class__
+ new_s_obj = SomeObject.__new__(s_obj.__class__)
dic = new_s_obj.__dict__ = s_obj.__dict__.copy()
if 'const' in dic:
del new_s_obj.const
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -456,6 +456,20 @@
return ''.join(g(n))
s = a.build_types(f, [int])
assert s.knowntype == str
+ assert s.no_nul
+
+ def test_str_split(self):
+ a = self.RPythonAnnotator()
+ def g(n):
+ if n:
+ return "test string"
+ def f(n):
+ if n:
+ return g(n).split(' ')
+ s = a.build_types(f, [int])
+ assert isinstance(s, annmodel.SomeList)
+ s_item = s.listdef.listitem.s_value
+ assert s_item.no_nul
def test_str_splitlines(self):
a = self.RPythonAnnotator()
@@ -465,6 +479,18 @@
assert isinstance(s, annmodel.SomeList)
assert s.listdef.listitem.resized
+ def test_str_strip(self):
+ a = self.RPythonAnnotator()
+ def f(n, a_str):
+ if n == 0:
+ return a_str.strip(' ')
+ elif n == 1:
+ return a_str.rstrip(' ')
+ else:
+ return a_str.lstrip(' ')
+ s = a.build_types(f, [int, annmodel.SomeString(no_nul=True)])
+ assert s.no_nul
+
def test_str_mul(self):
a = self.RPythonAnnotator()
def f(a_str):
@@ -1841,7 +1867,7 @@
return obj.indirect()
a = self.RPythonAnnotator()
s = a.build_types(f, [bool])
- assert s == annmodel.SomeString(can_be_None=True)
+ assert annmodel.SomeString(can_be_None=True).contains(s)
def test_dont_see_AttributeError_clause(self):
class Stuff:
@@ -2018,6 +2044,37 @@
s = a.build_types(g, [int])
assert not s.can_be_None
+ def test_string_noNUL_canbeNone(self):
+ def f(a):
+ if a:
+ return "abc"
+ else:
+ return None
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert s.can_be_None
+ assert s.no_nul
+
+ def test_str_or_None(self):
+ def f(a):
+ if a:
+ return "abc"
+ else:
+ return None
+ def g(a):
+ x = f(a)
+ #assert x is not None
+ if x is None:
+ return "abcd"
+ return x
+ if isinstance(x, str):
+ return x
+ return "impossible"
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert s.can_be_None
+ assert s.no_nul
+
def test_emulated_pbc_call_simple(self):
def f(a,b):
return a + b
@@ -2071,6 +2128,19 @@
assert isinstance(s, annmodel.SomeIterator)
assert s.variant == ('items',)
+ def test_iteritems_str0(self):
+ def it(d):
+ return d.iteritems()
+ def f():
+ d0 = {'1a': '2a', '3': '4'}
+ for item in it(d0):
+ return "%s=%s" % item
+ raise ValueError
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [])
+ assert isinstance(s, annmodel.SomeString)
+ assert s.no_nul
+
def test_non_none_and_none_with_isinstance(self):
class A(object):
pass
diff --git a/pypy/annotation/unaryop.py b/pypy/annotation/unaryop.py
--- a/pypy/annotation/unaryop.py
+++ b/pypy/annotation/unaryop.py
@@ -480,13 +480,13 @@
return SomeInteger(nonneg=True)
def method_strip(str, chr):
- return str.basestringclass()
+ return str.basestringclass(no_nul=str.no_nul)
def method_lstrip(str, chr):
- return str.basestringclass()
+ return str.basestringclass(no_nul=str.no_nul)
def method_rstrip(str, chr):
- return str.basestringclass()
+ return str.basestringclass(no_nul=str.no_nul)
def method_join(str, s_list):
if s_None.contains(s_list):
@@ -497,7 +497,8 @@
if isinstance(str, SomeUnicodeString):
return immutablevalue(u"")
return immutablevalue("")
- return str.basestringclass()
+ no_nul = str.no_nul and s_item.no_nul
+ return str.basestringclass(no_nul=no_nul)
def iter(str):
return SomeIterator(str)
@@ -508,18 +509,21 @@
def method_split(str, patt, max=-1):
getbookkeeper().count("str_split", str, patt)
- return getbookkeeper().newlist(str.basestringclass())
+ s_item = str.basestringclass(no_nul=str.no_nul)
+ return getbookkeeper().newlist(s_item)
def method_rsplit(str, patt, max=-1):
getbookkeeper().count("str_rsplit", str, patt)
- return getbookkeeper().newlist(str.basestringclass())
+ s_item = str.basestringclass(no_nul=str.no_nul)
+ return getbookkeeper().newlist(s_item)
def method_replace(str, s1, s2):
return str.basestringclass()
def getslice(str, s_start, s_stop):
check_negative_slice(s_start, s_stop)
- return str.basestringclass()
+ result = str.basestringclass(no_nul=str.no_nul)
+ return result
class __extend__(SomeUnicodeString):
def method_encode(uni, s_enc):
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -123,6 +123,9 @@
default="off"),
# jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default)
BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None),
+ BoolOption("check_str_without_nul",
+ "Forbid NUL chars in strings in some external function calls",
+ default=False, cmdline=None),
# misc
BoolOption("verbose", "Print extra information", default=False),
diff --git a/pypy/doc/Makefile b/pypy/doc/Makefile
--- a/pypy/doc/Makefile
+++ b/pypy/doc/Makefile
@@ -81,6 +81,7 @@
"run these through (pdf)latex."
man:
+ python config/generate.py
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man"
diff --git a/pypy/doc/commandline_ref.rst b/pypy/doc/commandline_ref.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/commandline_ref.rst
@@ -0,0 +1,10 @@
+Command line reference
+======================
+
+Manual pages
+------------
+
+.. toctree::
+ :maxdepth: 1
+
+ man/pypy.1.rst
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -45,9 +45,9 @@
# built documents.
#
# The short X.Y version.
-version = '1.7'
+version = '1.8'
# The full version, including alpha/beta/rc tags.
-release = '1.7'
+release = '1.8'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/doc/config/translation.check_str_without_nul.txt b/pypy/doc/config/translation.check_str_without_nul.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/translation.check_str_without_nul.txt
@@ -0,0 +1,5 @@
+If turned on, the annotator will keep track of which strings can
+potentially contain NUL characters, and complain if one such string
+is passed to some external functions --- e.g. if it is used as a
+filename in os.open(). Defaults to False because it is usually more
+pain than benefit, but turned on by targetpypystandalone.
diff --git a/pypy/doc/config/translation.log.txt b/pypy/doc/config/translation.log.txt
--- a/pypy/doc/config/translation.log.txt
+++ b/pypy/doc/config/translation.log.txt
@@ -2,4 +2,4 @@
These must be enabled by setting the PYPYLOG environment variable.
The exact set of features supported by PYPYLOG is described in
-pypy/translation/c/src/debug.h.
+pypy/translation/c/src/debug_print.h.
diff --git a/pypy/doc/garbage_collection.rst b/pypy/doc/garbage_collection.rst
--- a/pypy/doc/garbage_collection.rst
+++ b/pypy/doc/garbage_collection.rst
@@ -142,10 +142,9 @@
So as a first approximation, when compared to the Hybrid GC, the
Minimark GC saves one word of memory per old object.
-There are a number of environment variables that can be tweaked to
-influence the GC. (Their default value should be ok for most usages.)
-You can read more about them at the start of
-`pypy/rpython/memory/gc/minimark.py`_.
+There are :ref:`a number of environment variables
+<minimark-environment-variables>` that can be tweaked to influence the
+GC. (Their default value should be ok for most usages.)
In more detail:
@@ -211,5 +210,4 @@
are preserved. If the object dies then the pre-reserved location
becomes free garbage, to be collected at the next major collection.
-
.. include:: _ref.txt
diff --git a/pypy/doc/gc_info.rst b/pypy/doc/gc_info.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/gc_info.rst
@@ -0,0 +1,53 @@
+Garbage collector configuration
+===============================
+
+.. _minimark-environment-variables:
+
+Minimark
+--------
+
+PyPy's default ``minimark`` garbage collector is configurable through
+several environment variables:
+
+``PYPY_GC_NURSERY``
+ The nursery size.
+ Defaults to ``4MB``.
+ Small values (like 1 or 1KB) are useful for debugging.
+
+``PYPY_GC_MAJOR_COLLECT``
+ Major collection memory factor.
+ Default is ``1.82``, which means trigger a major collection when the
+ memory consumed equals 1.82 times the memory really used at the end
+ of the previous major collection.
+
+``PYPY_GC_GROWTH``
+ Major collection threshold's max growth rate.
+ Default is ``1.4``.
+ Useful to collect more often than normally on sudden memory growth,
+ e.g. when there is a temporary peak in memory usage.
+
+``PYPY_GC_MAX``
+ The max heap size.
+ If coming near this limit, it will first collect more often, then
+ raise an RPython MemoryError, and if that is not enough, crash the
+ program with a fatal error.
+ Try values like ``1.6GB``.
+
+``PYPY_GC_MAX_DELTA``
+ The major collection threshold will never be set to more than
+ ``PYPY_GC_MAX_DELTA`` the amount really used after a collection.
+ Defaults to 1/8th of the total RAM size (which is constrained to be
+ at most 2/3/4GB on 32-bit systems).
+ Try values like ``200MB``.
+
+``PYPY_GC_MIN``
+ Don't collect while the memory size is below this limit.
+ Useful to avoid spending all the time in the GC in very small
+ programs.
+ Defaults to 8 times the nursery.
+
+``PYPY_GC_DEBUG``
+ Enable extra checks around collections that are too slow for normal
+ use.
+ Values are ``0`` (off), ``1`` (on major collections) or ``2`` (also
+ on minor collections).
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -353,10 +353,12 @@
getting-started-dev.rst
windows.rst
faq.rst
+ commandline_ref.rst
architecture.rst
coding-guide.rst
cpython_differences.rst
garbage_collection.rst
+ gc_info.rst
interpreter.rst
objspace.rst
__pypy__-module.rst
diff --git a/pypy/doc/man/pypy.1.rst b/pypy/doc/man/pypy.1.rst
--- a/pypy/doc/man/pypy.1.rst
+++ b/pypy/doc/man/pypy.1.rst
@@ -24,6 +24,9 @@
-S
Do not ``import site`` on initialization.
+-s
+ Don't add the user site directory to `sys.path`.
+
-u
Unbuffered binary ``stdout`` and ``stderr``.
@@ -39,6 +42,9 @@
-E
Ignore environment variables (such as ``PYTHONPATH``).
+-B
+ Disable writing bytecode (``.pyc``) files.
+
--version
Print the PyPy version.
@@ -84,6 +90,64 @@
Optimizations to enabled or ``all``.
Warning, this option is dangerous, and should be avoided.
+ENVIRONMENT
+===========
+
+``PYTHONPATH``
+ Add directories to pypy's module search path.
+ The format is the same as shell's ``PATH``.
+
+``PYTHONSTARTUP``
+ A script referenced by this variable will be executed before the
+ first prompt is displayed, in interactive mode.
+
+``PYTHONDONTWRITEBYTECODE``
+ If set to a non-empty value, equivalent to the ``-B`` option.
+ Disable writing ``.pyc`` files.
+
+``PYTHONINSPECT``
+ If set to a non-empty value, equivalent to the ``-i`` option.
+ Inspect interactively after running the specified script.
+
+``PYTHONIOENCODING``
+ If this is set, it overrides the encoding used for
+ *stdin*/*stdout*/*stderr*.
+ The syntax is *encodingname*:*errorhandler*
+ The *errorhandler* part is optional and has the same meaning as in
+ `str.encode`.
+
+``PYTHONNOUSERSITE``
+ If set to a non-empty value, equivalent to the ``-s`` option.
+ Don't add the user site directory to `sys.path`.
+
+``PYTHONWARNINGS``
+ If set, equivalent to the ``-W`` option (warning control).
+ The value should be a comma-separated list of ``-W`` parameters.
+
+``PYPYLOG``
+ If set to a non-empty value, enable logging, the format is:
+
+ *fname*
+ logging for profiling: includes all
+ ``debug_start``/``debug_stop`` but not any nested
+ ``debug_print``.
+ *fname* can be ``-`` to log to *stderr*.
+
+ ``:``\ *fname*
+ Full logging, including ``debug_print``.
+
+ *prefix*\ ``:``\ *fname*
+ Conditional logging.
+ Multiple prefixes can be specified, comma-separated.
+ Only sections whose name match the prefix will be logged.
+
+ ``PYPYLOG``\ =\ ``jit-log-opt,jit-backend:``\ *logfile* will
+ generate a log suitable for *jitviewer*, a tool for debugging
+ performance issues under PyPy.
+
+.. include:: ../gc_info.rst
+ :start-line: 7
+
SEE ALSO
========
diff --git a/pypy/doc/release-1.8.0.rst b/pypy/doc/release-1.8.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-1.8.0.rst
@@ -0,0 +1,52 @@
+============================
+PyPy 1.8 - business as usual
+============================
+
+We're pleased to announce the 1.8 release of PyPy. As became a habit, this
+release brings a lot of bugfixes, performance and memory improvements over
+the 1.7 release. The main highlight of the release is the introduction of
+list strategies which makes homogenous lists more efficient both in terms
+of performance and memory. Otherwise it's "business as usual" in the sense
+that performance improved roughly 10% on average since the previous release.
+You can download the PyPy 1.8 release here:
+
+ http://pypy.org/download.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 1.8 and cpython 2.7.1`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 32/64 or
+Windows 32. Windows 64 work is ongoing, but not yet natively supported.
+
+.. _`pypy 1.8 and cpython 2.7.1`: http://speed.pypy.org
+
+
+Highlights
+==========
+
+* List strategies. Now lists that contain only ints or only floats should
+ be as efficient as storing them in a binary-packed array. It also improves
+ the JIT performance in places that use such lists. There are also special
+ strategies for unicode and string lists.
+
+* As usual, numerous performance improvements. There are too many examples
+ of python constructs that now should behave faster to list them.
+
+* Bugfixes and compatibility fixes with CPython.
+
+* Windows fixes.
+
+* NumPy effort progress; for the exact list of things that have been done,
+ consult the `numpy status page`_. A tentative list of things that has
+ been done:
+
+ xxxx # list it, multidim arrays in particular
+
+* Fundraising XXX
+
+.. _`numpy status page`: xxx
+.. _`numpy status update blog report`: xxx
diff --git a/pypy/interpreter/astcompiler/optimize.py b/pypy/interpreter/astcompiler/optimize.py
--- a/pypy/interpreter/astcompiler/optimize.py
+++ b/pypy/interpreter/astcompiler/optimize.py
@@ -302,8 +302,7 @@
# narrow builds will return a surrogate. In both
# the cases skip the optimization in order to
# produce compatible pycs.
- if (self.space.isinstance_w(w_obj, self.space.w_unicode)
- and
+ if (self.space.isinstance_w(w_obj, self.space.w_unicode) and
self.space.isinstance_w(w_const, self.space.w_unicode)):
unistr = self.space.unicode_w(w_const)
if len(unistr) == 1:
@@ -311,7 +310,7 @@
else:
ch = 0
if (ch > 0xFFFF or
- (MAXUNICODE == 0xFFFF and 0xD800 <= ch <= 0xDFFFF)):
+ (MAXUNICODE == 0xFFFF and 0xD800 <= ch <= 0xDFFF)):
return subs
return ast.Const(w_const, subs.lineno, subs.col_offset)
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -838,7 +838,7 @@
# Just checking this doesn't crash out
self.count_instructions(source)
- def test_const_fold_unicode_subscr(self):
+ def test_const_fold_unicode_subscr(self, monkeypatch):
source = """def f():
return u"abc"[0]
"""
@@ -853,6 +853,14 @@
assert counts == {ops.LOAD_CONST: 2, ops.BINARY_SUBSCR: 1,
ops.RETURN_VALUE: 1}
+ monkeypatch.setattr(optimize, "MAXUNICODE", 0xFFFF)
+ source = """def f():
+ return u"\uE01F"[0]
+ """
+ counts = self.count_instructions(source)
+ assert counts == {ops.LOAD_CONST: 1, ops.RETURN_VALUE: 1}
+ monkeypatch.undo()
+
# getslice is not yet optimized.
# Still, check a case which yields the empty string.
source = """def f():
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1312,6 +1312,15 @@
def str_w(self, w_obj):
return w_obj.str_w(self)
+ def str0_w(self, w_obj):
+ "Like str_w, but rejects strings with NUL bytes."
+ from pypy.rlib import rstring
+ result = w_obj.str_w(self)
+ if '\x00' in result:
+ raise OperationError(self.w_TypeError, self.wrap(
+ 'argument must be a string without NUL characters'))
+ return rstring.assert_str0(result)
+
def int_w(self, w_obj):
return w_obj.int_w(self)
@@ -1331,6 +1340,15 @@
def unicode_w(self, w_obj):
return w_obj.unicode_w(self)
+ def unicode0_w(self, w_obj):
+ "Like unicode_w, but rejects strings with NUL bytes."
+ from pypy.rlib import rstring
+ result = w_obj.unicode_w(self)
+ if u'\x00' in result:
+ raise OperationError(self.w_TypeError, self.wrap(
+ 'argument must be a unicode string without NUL characters'))
+ return rstring.assert_str0(result)
+
def realunicode_w(self, w_obj):
# Like unicode_w, but only works if w_obj is really of type
# 'unicode'.
@@ -1629,6 +1647,9 @@
'UnicodeEncodeError',
'UnicodeDecodeError',
]
+
+if sys.platform.startswith("win"):
+ ObjSpace.ExceptionTable += ['WindowsError']
## Irregular part of the interface:
#
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -130,6 +130,9 @@
def visit_str_or_None(self, el, app_sig):
self.checked_space_method(el, app_sig)
+ def visit_str0(self, el, app_sig):
+ self.checked_space_method(el, app_sig)
+
def visit_nonnegint(self, el, app_sig):
self.checked_space_method(el, app_sig)
@@ -249,6 +252,9 @@
def visit_str_or_None(self, typ):
self.run_args.append("space.str_or_None_w(%s)" % (self.scopenext(),))
+ def visit_str0(self, typ):
+ self.run_args.append("space.str0_w(%s)" % (self.scopenext(),))
+
def visit_nonnegint(self, typ):
self.run_args.append("space.gateway_nonnegint_w(%s)" % (
self.scopenext(),))
@@ -383,6 +389,9 @@
def visit_str_or_None(self, typ):
self.unwrap.append("space.str_or_None_w(%s)" % (self.nextarg(),))
+ def visit_str0(self, typ):
+ self.unwrap.append("space.str0_w(%s)" % (self.nextarg(),))
+
def visit_nonnegint(self, typ):
self.unwrap.append("space.gateway_nonnegint_w(%s)" % (self.nextarg(),))
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -50,7 +50,7 @@
space.call_method(self.w_dict, 'update', self.w_initialdict)
for w_submodule in self.submodules_w:
- name = space.str_w(w_submodule.w_name)
+ name = space.str0_w(w_submodule.w_name)
space.setitem(self.w_dict, space.wrap(name.split(".")[-1]), w_submodule)
space.getbuiltinmodule(name)
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -31,7 +31,8 @@
def install(self):
"""NOT_RPYTHON: installs this module into space.builtin_modules"""
w_mod = self.space.wrap(self)
- self.space.builtin_modules[self.space.unwrap(self.w_name)] = w_mod
+ modulename = self.space.str0_w(self.w_name)
+ self.space.builtin_modules[modulename] = w_mod
def setup_after_space_initialization(self):
"""NOT_RPYTHON: to allow built-in modules to do some more setup
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -178,6 +178,14 @@
res = self.space.interp_w(Function, w(None), can_be_None=True)
assert res is None
+ def test_str0_w(self):
+ space = self.space
+ w = space.wrap
+ assert space.str0_w(w("123")) == "123"
+ exc = space.raises_w(space.w_TypeError, space.str0_w, w("123\x004"))
+ assert space.unicode0_w(w(u"123")) == u"123"
+ exc = space.raises_w(space.w_TypeError, space.unicode0_w, w(u"123\x004"))
+
def test_getindex_w(self):
w_instance1 = self.space.appexec([], """():
class X(object):
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -780,6 +780,9 @@
self.overflow_flag = ovf
return z
+ def op_keepalive(self, _, x):
+ pass
+
# ----------
# delegating to the builtins do_xxx() (done automatically for simple cases)
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -1463,6 +1463,9 @@
if jump_op is not None and jump_op.getdescr() is descr:
self._compute_hint_frame_locations_from_descr(descr)
+ def consider_keepalive(self, op):
+ pass
+
def not_implemented_op(self, op):
not_implemented("not implemented operation: %s" % op.getopname())
diff --git a/pypy/jit/codewriter/flatten.py b/pypy/jit/codewriter/flatten.py
--- a/pypy/jit/codewriter/flatten.py
+++ b/pypy/jit/codewriter/flatten.py
@@ -162,7 +162,9 @@
if len(block.exits) == 1:
# A single link, fall-through
link = block.exits[0]
- assert link.exitcase is None
+ assert link.exitcase in (None, False, True)
+ # the cases False or True should not really occur, but can show
+ # up in the manually hacked graphs for generators...
self.make_link(link)
#
elif block.exitswitch is c_last_exception:
diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py
--- a/pypy/jit/codewriter/policy.py
+++ b/pypy/jit/codewriter/policy.py
@@ -48,7 +48,7 @@
mod = func.__module__ or '?'
if mod.startswith('pypy.rpython.module.'):
return True
- if mod.startswith('pypy.translator.'): # XXX wtf?
+ if mod == 'pypy.translator.goal.nanos': # more helpers
return True
return False
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -254,6 +254,9 @@
assert isinstance(x, r_longlong) # 32-bit
return BoxFloat(x)
+def do_keepalive(cpu, _, x):
+ pass
+
# ____________________________________________________________
##def do_force_token(cpu):
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -974,13 +974,13 @@
any_operation = len(self.metainterp.history.operations) > 0
jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
self.verify_green_args(jitdriver_sd, greenboxes)
- self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion,
+ self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.portal_call_depth,
greenboxes)
if self.metainterp.seen_loop_header_for_jdindex < 0:
if not any_operation:
return
- if self.metainterp.in_recursion or not self.metainterp.get_procedure_token(greenboxes, True):
+ if self.metainterp.portal_call_depth or not self.metainterp.get_procedure_token(greenboxes, True):
if not jitdriver_sd.no_loop_header:
return
# automatically add a loop_header if there is none
@@ -992,7 +992,7 @@
self.metainterp.seen_loop_header_for_jdindex = -1
#
- if not self.metainterp.in_recursion:
+ if not self.metainterp.portal_call_depth:
assert jitdriver_sd is self.metainterp.jitdriver_sd
# Set self.pc to point to jit_merge_point instead of just after:
# if reached_loop_header() raises SwitchToBlackhole, then the
@@ -1028,11 +1028,11 @@
assembler_call=True)
raise ChangeFrame
- def debug_merge_point(self, jitdriver_sd, jd_index, in_recursion, greenkey):
+ def debug_merge_point(self, jitdriver_sd, jd_index, portal_call_depth, greenkey):
# debugging: produce a DEBUG_MERGE_POINT operation
loc = jitdriver_sd.warmstate.get_location_str(greenkey)
debug_print(loc)
- args = [ConstInt(jd_index), ConstInt(in_recursion)] + greenkey
+ args = [ConstInt(jd_index), ConstInt(portal_call_depth)] + greenkey
self.metainterp.history.record(rop.DEBUG_MERGE_POINT, args, None)
@arguments("box", "label")
@@ -1346,12 +1346,16 @@
resbox = self.metainterp.execute_and_record_varargs(
rop.CALL_MAY_FORCE, allboxes, descr=descr)
self.metainterp.vrefs_after_residual_call()
+ vablebox = None
if assembler_call:
- self.metainterp.direct_assembler_call(assembler_call_jd)
+ vablebox = self.metainterp.direct_assembler_call(
+ assembler_call_jd)
if resbox is not None:
self.make_result_of_lastop(resbox)
self.metainterp.vable_after_residual_call()
self.generate_guard(rop.GUARD_NOT_FORCED, None)
+ if vablebox is not None:
+ self.metainterp.history.record(rop.KEEPALIVE, [vablebox], None)
self.metainterp.handle_possible_exception()
return resbox
else:
@@ -1552,7 +1556,7 @@
# ____________________________________________________________
class MetaInterp(object):
- in_recursion = 0
+ portal_call_depth = 0
cancel_count = 0
def __init__(self, staticdata, jitdriver_sd):
@@ -1587,7 +1591,7 @@
def newframe(self, jitcode, greenkey=None):
if jitcode.is_portal:
- self.in_recursion += 1
+ self.portal_call_depth += 1
if greenkey is not None and self.is_main_jitcode(jitcode):
self.portal_trace_positions.append(
(greenkey, len(self.history.operations)))
@@ -1603,7 +1607,7 @@
frame = self.framestack.pop()
jitcode = frame.jitcode
if jitcode.is_portal:
- self.in_recursion -= 1
+ self.portal_call_depth -= 1
if frame.greenkey is not None and self.is_main_jitcode(jitcode):
self.portal_trace_positions.append(
(None, len(self.history.operations)))
@@ -1662,17 +1666,17 @@
raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base())
def check_recursion_invariant(self):
- in_recursion = -1
+ portal_call_depth = -1
for frame in self.framestack:
jitcode = frame.jitcode
assert jitcode.is_portal == len([
jd for jd in self.staticdata.jitdrivers_sd
if jd.mainjitcode is jitcode])
if jitcode.is_portal:
- in_recursion += 1
- if in_recursion != self.in_recursion:
- print "in_recursion problem!!!"
- print in_recursion, self.in_recursion
+ portal_call_depth += 1
+ if portal_call_depth != self.portal_call_depth:
+ print "portal_call_depth problem!!!"
+ print portal_call_depth, self.portal_call_depth
for frame in self.framestack:
jitcode = frame.jitcode
if jitcode.is_portal:
@@ -2183,11 +2187,11 @@
def initialize_state_from_start(self, original_boxes):
# ----- make a new frame -----
- self.in_recursion = -1 # always one portal around
+ self.portal_call_depth = -1 # always one portal around
self.framestack = []
f = self.newframe(self.jitdriver_sd.mainjitcode)
f.setup_call(original_boxes)
- assert self.in_recursion == 0
+ assert self.portal_call_depth == 0
self.virtualref_boxes = []
self.initialize_withgreenfields(original_boxes)
self.initialize_virtualizable(original_boxes)
@@ -2198,7 +2202,7 @@
# otherwise the jit_virtual_refs are left in a dangling state.
rstack._stack_criticalcode_start()
try:
- self.in_recursion = -1 # always one portal around
+ self.portal_call_depth = -1 # always one portal around
self.history = history.History()
inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
self.history.inputargs = [box for box in inputargs_and_holes if box]
@@ -2478,6 +2482,15 @@
token = warmrunnerstate.get_assembler_token(greenargs)
op = op.copy_and_change(rop.CALL_ASSEMBLER, args=args, descr=token)
self.history.operations.append(op)
+ #
+ # To fix an obscure issue, make sure the vable stays alive
+ # longer than the CALL_ASSEMBLER operation. We do it by
+ # inserting explicitly an extra KEEPALIVE operation.
+ jd = token.outermost_jitdriver_sd
+ if jd.index_of_virtualizable >= 0:
+ return args[jd.index_of_virtualizable]
+ else:
+ return None
# ____________________________________________________________
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -503,6 +503,7 @@
'COPYUNICODECONTENT/5',
'QUASIIMMUT_FIELD/1d', # [objptr], descr=SlowMutateDescr
'RECORD_KNOWN_CLASS/2', # [objptr, clsptr]
+ 'KEEPALIVE/1',
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
'_CALL_FIRST',
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -322,6 +322,17 @@
res = self.interp_operations(f, [42])
assert res == ord(u"?")
+ def test_char_in_constant_string(self):
+ def g(string):
+ return '\x00' in string
+ def f():
+ if g('abcdef'): return -60
+ if not g('abc\x00ef'): return -61
+ return 42
+ res = self.interp_operations(f, [])
+ assert res == 42
+ self.check_operations_history({'finish': 1}) # nothing else
+
def test_residual_call(self):
@dont_look_inside
def externfn(x, y):
@@ -3695,6 +3706,18 @@
# here it works again
self.check_operations_history(guard_class=0, record_known_class=1)
+ def test_generator(self):
+ def g(n):
+ yield n+1
+ yield n+2
+ yield n+3
+ def f(n):
+ gen = g(n)
+ return gen.next() * gen.next() * gen.next()
+ res = self.interp_operations(f, [10])
+ assert res == 11 * 12 * 13
+ self.check_operations_history(int_add=3, int_mul=2)
+
class TestLLtype(BaseLLtypeTests, LLJitMixin):
def test_tagged(self):
diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py
--- a/pypy/module/_ffi/test/test__ffi.py
+++ b/pypy/module/_ffi/test/test__ffi.py
@@ -190,6 +190,7 @@
def test_convert_strings_to_char_p(self):
"""
+ DLLEXPORT
long mystrlen(char* s)
{
long len = 0;
@@ -215,6 +216,7 @@
def test_convert_unicode_to_unichar_p(self):
"""
#include <wchar.h>
+ DLLEXPORT
long mystrlen_u(wchar_t* s)
{
long len = 0;
@@ -241,6 +243,7 @@
def test_keepalive_temp_buffer(self):
"""
+ DLLEXPORT
char* do_nothing(char* s)
{
return s;
@@ -525,5 +528,7 @@
from _ffi import CDLL, types
libfoo = CDLL(self.libfoo_name)
raises(AttributeError, "libfoo.getfunc('I_do_not_exist', [], types.void)")
+ if self.iswin32:
+ skip("unix specific")
libnone = CDLL(None)
raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py
--- a/pypy/module/_file/test/test_file.py
+++ b/pypy/module/_file/test/test_file.py
@@ -265,6 +265,13 @@
if option.runappdirect:
py.test.skip("works with internals of _file impl on py.py")
+ import platform
+ if platform.system() == 'Windows':
+ # XXX This test crashes until someone implements something like
+ # XXX verify_fd from
+ # XXX http://hg.python.org/cpython/file/80ddbd822227/Modules/posixmodule.c#l434
+ # XXX and adds it to fopen
+ assert False
state = [0]
def read(fd, n=None):
diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py
--- a/pypy/module/bz2/interp_bz2.py
+++ b/pypy/module/bz2/interp_bz2.py
@@ -328,7 +328,7 @@
if basemode == "a":
raise OperationError(space.w_ValueError,
space.wrap("cannot append to bz2 file"))
- stream = open_path_helper(space.str_w(w_path), os_flags, False)
+ stream = open_path_helper(space.str0_w(w_path), os_flags, False)
if reading:
bz2stream = ReadBZ2Filter(space, stream, buffering)
buffering = 0 # by construction, the ReadBZ2Filter acts like
diff --git a/pypy/module/cpyext/include/pythonrun.h b/pypy/module/cpyext/include/pythonrun.h
--- a/pypy/module/cpyext/include/pythonrun.h
+++ b/pypy/module/cpyext/include/pythonrun.h
@@ -13,6 +13,7 @@
#define Py_FrozenFlag 0
#define Py_VerboseFlag 0
+#define Py_DebugFlag 1
typedef struct {
int cf_flags; /* bitmask of CO_xxx flags relevant to future */
diff --git a/pypy/module/gc/interp_gc.py b/pypy/module/gc/interp_gc.py
--- a/pypy/module/gc/interp_gc.py
+++ b/pypy/module/gc/interp_gc.py
@@ -49,7 +49,7 @@
# ____________________________________________________________
- at unwrap_spec(filename=str)
+ at unwrap_spec(filename='str0')
def dump_heap_stats(space, filename):
tb = rgc._heap_stats()
if not tb:
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -138,7 +138,7 @@
ctxt_package = None
if ctxt_w_package is not None and ctxt_w_package is not space.w_None:
try:
- ctxt_package = space.str_w(ctxt_w_package)
+ ctxt_package = space.str0_w(ctxt_w_package)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
@@ -187,7 +187,7 @@
ctxt_name = None
if ctxt_w_name is not None:
try:
- ctxt_name = space.str_w(ctxt_w_name)
+ ctxt_name = space.str0_w(ctxt_w_name)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
@@ -230,7 +230,7 @@
return rel_modulename, rel_level
- at unwrap_spec(name=str, level=int)
+ at unwrap_spec(name='str0', level=int)
def importhook(space, name, w_globals=None,
w_locals=None, w_fromlist=None, level=-1):
modulename = name
@@ -377,8 +377,8 @@
fromlist_w = space.fixedview(w_all)
for w_name in fromlist_w:
if try_getattr(space, w_mod, w_name) is None:
- load_part(space, w_path, prefix, space.str_w(w_name), w_mod,
- tentative=1)
+ load_part(space, w_path, prefix, space.str0_w(w_name),
+ w_mod, tentative=1)
return w_mod
else:
return first
@@ -432,7 +432,7 @@
def __init__(self, space):
pass
- @unwrap_spec(path=str)
+ @unwrap_spec(path='str0')
def descr_init(self, space, path):
if not path:
raise OperationError(space.w_ImportError, space.wrap(
@@ -513,7 +513,7 @@
if w_loader:
return FindInfo.fromLoader(w_loader)
- path = space.str_w(w_pathitem)
+ path = space.str0_w(w_pathitem)
filepart = os.path.join(path, partname)
if os.path.isdir(filepart) and case_ok(filepart):
initfile = os.path.join(filepart, '__init__')
@@ -671,7 +671,7 @@
space.wrap("reload() argument must be module"))
w_modulename = space.getattr(w_module, space.wrap("__name__"))
- modulename = space.str_w(w_modulename)
+ modulename = space.str0_w(w_modulename)
if not space.is_w(check_sys_modules(space, w_modulename), w_module):
raise operationerrfmt(
space.w_ImportError,
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -44,7 +44,7 @@
return space.interp_w(W_File, w_file).stream
def find_module(space, w_name, w_path=None):
- name = space.str_w(w_name)
+ name = space.str0_w(w_name)
if space.is_w(w_path, space.w_None):
w_path = None
@@ -75,7 +75,7 @@
def load_module(space, w_name, w_file, w_filename, w_info):
w_suffix, w_filemode, w_modtype = space.unpackiterable(w_info)
- filename = space.str_w(w_filename)
+ filename = space.str0_w(w_filename)
filemode = space.str_w(w_filemode)
if space.is_w(w_file, space.w_None):
stream = None
@@ -92,7 +92,7 @@
space, w_name, find_info, reuse=True)
def load_source(space, w_modulename, w_filename, w_file=None):
- filename = space.str_w(w_filename)
+ filename = space.str0_w(w_filename)
stream = get_file(space, w_file, filename, 'U')
@@ -105,7 +105,7 @@
stream.close()
return w_mod
- at unwrap_spec(filename=str)
+ at unwrap_spec(filename='str0')
def _run_compiled_module(space, w_modulename, filename, w_file, w_module):
# the function 'imp._run_compiled_module' is a pypy-only extension
stream = get_file(space, w_file, filename, 'rb')
@@ -119,7 +119,7 @@
if space.is_w(w_file, space.w_None):
stream.close()
- at unwrap_spec(filename=str)
+ at unwrap_spec(filename='str0')
def load_compiled(space, w_modulename, filename, w_file=None):
w_mod = space.wrap(Module(space, w_modulename))
importing._prepare_module(space, w_mod, filename, None)
@@ -138,7 +138,7 @@
return space.wrap(Module(space, w_name, add_package=False))
def init_builtin(space, w_name):
- name = space.str_w(w_name)
+ name = space.str0_w(w_name)
if name not in space.builtin_modules:
return
if space.finditem(space.sys.get('modules'), w_name) is not None:
@@ -151,7 +151,7 @@
return None
def is_builtin(space, w_name):
- name = space.str_w(w_name)
+ name = space.str0_w(w_name)
if name not in space.builtin_modules:
return space.wrap(0)
if space.finditem(space.sys.get('modules'), w_name) is not None:
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -98,6 +98,10 @@
('bitwise_not', 'invert'),
('isnan', 'isnan'),
('isinf', 'isinf'),
+ ('logical_and', 'logical_and'),
+ ('logical_xor', 'logical_xor'),
+ ('logical_not', 'logical_not'),
+ ('logical_or', 'logical_or'),
]:
interpleveldefs[exposed] = "interp_ufuncs.get(space).%s" % impl
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -80,6 +80,7 @@
descr_sub = _binop_impl("subtract")
descr_mul = _binop_impl("multiply")
descr_div = _binop_impl("divide")
+ descr_truediv = _binop_impl("true_divide")
descr_pow = _binop_impl("power")
descr_eq = _binop_impl("equal")
descr_ne = _binop_impl("not_equal")
@@ -174,6 +175,7 @@
__sub__ = interp2app(W_GenericBox.descr_sub),
__mul__ = interp2app(W_GenericBox.descr_mul),
__div__ = interp2app(W_GenericBox.descr_div),
+ __truediv__ = interp2app(W_GenericBox.descr_truediv),
__pow__ = interp2app(W_GenericBox.descr_pow),
__radd__ = interp2app(W_GenericBox.descr_radd),
diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
--- a/pypy/module/micronumpy/interp_iter.py
+++ b/pypy/module/micronumpy/interp_iter.py
@@ -86,8 +86,9 @@
def apply_transformations(self, arr, transformations):
v = self
- for transform in transformations:
- v = v.transform(arr, transform)
+ if transformations is not None:
+ for transform in transformations:
+ v = v.transform(arr, transform)
return v
def transform(self, arr, t):
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -3,7 +3,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.module.micronumpy import (interp_ufuncs, interp_dtype, interp_boxes,
- signature, support)
+ signature, support, loop)
from pypy.module.micronumpy.strides import (calculate_slice_strides,
shape_agreement, find_shape_and_elems, get_shape_from_iterable,
calc_new_strides, to_coords)
@@ -12,39 +12,11 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib.rstring import StringBuilder
-from pypy.module.micronumpy.interp_iter import (ArrayIterator, OneDimIterator,
+from pypy.module.micronumpy.interp_iter import (ArrayIterator,
SkipLastAxisIterator, Chunk, ViewIterator)
from pypy.module.micronumpy.appbridge import get_appbridge_cache
-numpy_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['result_size', 'frame', 'ri', 'self', 'result'],
- get_printable_location=signature.new_printable_location('numpy'),
- name='numpy',
-)
-all_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['frame', 'self', 'dtype'],
- get_printable_location=signature.new_printable_location('all'),
- name='numpy_all',
-)
-any_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['frame', 'self', 'dtype'],
- get_printable_location=signature.new_printable_location('any'),
- name='numpy_any',
-)
-slice_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['self', 'frame', 'arr'],
- get_printable_location=signature.new_printable_location('slice'),
- name='numpy_slice',
-)
count_driver = jit.JitDriver(
greens=['shapelen'],
virtualizables=['frame'],
@@ -173,6 +145,8 @@
descr_prod = _reduce_ufunc_impl("multiply", True)
descr_max = _reduce_ufunc_impl("maximum")
descr_min = _reduce_ufunc_impl("minimum")
+ descr_all = _reduce_ufunc_impl('logical_and')
+ descr_any = _reduce_ufunc_impl('logical_or')
def _reduce_argmax_argmin_impl(op_name):
reduce_driver = jit.JitDriver(
@@ -212,40 +186,6 @@
return space.wrap(loop(self))
return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
- def _all(self):
- dtype = self.find_dtype()
- sig = self.find_sig()
- frame = sig.create_frame(self)
- shapelen = len(self.shape)
- while not frame.done():
- all_driver.jit_merge_point(sig=sig,
- shapelen=shapelen, self=self,
- dtype=dtype, frame=frame)
- if not dtype.itemtype.bool(sig.eval(frame, self)):
- return False
- frame.next(shapelen)
- return True
-
- def descr_all(self, space):
- return space.wrap(self._all())
-
- def _any(self):
- dtype = self.find_dtype()
- sig = self.find_sig()
- frame = sig.create_frame(self)
- shapelen = len(self.shape)
- while not frame.done():
- any_driver.jit_merge_point(sig=sig, frame=frame,
- shapelen=shapelen, self=self,
- dtype=dtype)
- if dtype.itemtype.bool(sig.eval(frame, self)):
- return True
- frame.next(shapelen)
- return False
-
- def descr_any(self, space):
- return space.wrap(self._any())
-
descr_argmax = _reduce_argmax_argmin_impl("max")
descr_argmin = _reduce_argmax_argmin_impl("min")
@@ -267,7 +207,7 @@
out_size = support.product(out_shape)
result = W_NDimArray(out_size, out_shape, dtype)
# This is the place to add fpypy and blas
- return multidim_dot(space, self.get_concrete(),
+ return multidim_dot(space, self.get_concrete(),
other.get_concrete(), result, dtype,
other_critical_dim)
@@ -280,6 +220,12 @@
def descr_get_ndim(self, space):
return space.wrap(len(self.shape))
+ def descr_get_itemsize(self, space):
+ return space.wrap(self.find_dtype().itemtype.get_element_size())
+
+ def descr_get_nbytes(self, space):
+ return space.wrap(self.size * self.find_dtype().itemtype.get_element_size())
+
@jit.unroll_safe
def descr_get_shape(self, space):
return space.newtuple([space.wrap(i) for i in self.shape])
@@ -507,7 +453,7 @@
w_shape = space.newtuple(args_w)
new_shape = get_shape_from_iterable(space, self.size, w_shape)
return self.reshape(space, new_shape)
-
+
def reshape(self, space, new_shape):
concrete = self.get_concrete()
# Since we got to here, prod(new_shape) == self.size
@@ -679,6 +625,9 @@
raise OperationError(space.w_NotImplementedError, space.wrap(
"non-int arg not supported"))
+ def compute_first_step(self, sig, frame):
+ pass
+
def convert_to_array(space, w_obj):
if isinstance(w_obj, BaseArray):
return w_obj
@@ -744,22 +693,9 @@
raise NotImplementedError
def compute(self):
- result = W_NDimArray(self.size, self.shape, self.find_dtype())
- shapelen = len(self.shape)
- sig = self.find_sig()
- frame = sig.create_frame(self)
- ri = ArrayIterator(self.size)
- while not ri.done():
- numpy_driver.jit_merge_point(sig=sig,
- shapelen=shapelen,
- result_size=self.size,
- frame=frame,
- ri=ri,
- self=self, result=result)
- result.setitem(ri.offset, sig.eval(frame, self))
- frame.next(shapelen)
- ri = ri.next(shapelen)
- return result
+ ra = ResultArray(self, self.size, self.shape, self.res_dtype)
+ loop.compute(ra)
+ return ra.left
def force_if_needed(self):
if self.forced_result is None:
@@ -817,7 +753,8 @@
def create_sig(self):
if self.forced_result is not None:
return self.forced_result.create_sig()
- return signature.Call1(self.ufunc, self.name, self.values.create_sig())
+ return signature.Call1(self.ufunc, self.name, self.calc_dtype,
+ self.values.create_sig())
class Call2(VirtualArray):
"""
@@ -858,6 +795,66 @@
return signature.Call2(self.ufunc, self.name, self.calc_dtype,
self.left.create_sig(), self.right.create_sig())
+class ResultArray(Call2):
+ def __init__(self, child, size, shape, dtype, res=None, order='C'):
+ if res is None:
+ res = W_NDimArray(size, shape, dtype, order)
+ Call2.__init__(self, None, 'assign', shape, dtype, dtype, res, child)
+
+ def create_sig(self):
+ return signature.ResultSignature(self.res_dtype, self.left.create_sig(),
+ self.right.create_sig())
+
+def done_if_true(dtype, val):
+ return dtype.itemtype.bool(val)
+
+def done_if_false(dtype, val):
+ return not dtype.itemtype.bool(val)
+
+class ReduceArray(Call2):
+ def __init__(self, func, name, identity, child, dtype):
+ self.identity = identity
+ Call2.__init__(self, func, name, [1], dtype, dtype, None, child)
+
+ def compute_first_step(self, sig, frame):
+ assert isinstance(sig, signature.ReduceSignature)
+ if self.identity is None:
+ frame.cur_value = sig.right.eval(frame, self.right).convert_to(
+ self.calc_dtype)
+ frame.next(len(self.right.shape))
+ else:
+ frame.cur_value = self.identity.convert_to(self.calc_dtype)
+
+ def create_sig(self):
+ if self.name == 'logical_and':
+ done_func = done_if_false
+ elif self.name == 'logical_or':
+ done_func = done_if_true
+ else:
+ done_func = None
+ return signature.ReduceSignature(self.ufunc, self.name, self.res_dtype,
+ signature.ScalarSignature(self.res_dtype),
+ self.right.create_sig(), done_func)
+
+class AxisReduce(Call2):
+ _immutable_fields_ = ['left', 'right']
+
+ def __init__(self, ufunc, name, identity, shape, dtype, left, right, dim):
+ Call2.__init__(self, ufunc, name, shape, dtype, dtype,
+ left, right)
+ self.dim = dim
+ self.identity = identity
+
+ def compute_first_step(self, sig, frame):
+ if self.identity is not None:
+ frame.identity = self.identity.convert_to(self.calc_dtype)
+
+ def create_sig(self):
+ return signature.AxisReduceSignature(self.ufunc, self.name,
+ self.res_dtype,
+ signature.ScalarSignature(self.res_dtype),
+ self.right.create_sig())
+
class SliceArray(Call2):
def __init__(self, shape, dtype, left, right, no_broadcast=False):
self.no_broadcast = no_broadcast
@@ -876,18 +873,6 @@
self.calc_dtype,
lsig, rsig)
-class AxisReduce(Call2):
- """ NOTE: this is only used as a container, you should never
- encounter such things in the wild. Remove this comment
- when we'll make AxisReduce lazy
- """
- _immutable_fields_ = ['left', 'right']
-
- def __init__(self, ufunc, name, shape, dtype, left, right, dim):
- Call2.__init__(self, ufunc, name, shape, dtype, dtype,
- left, right)
- self.dim = dim
-
class ConcreteArray(BaseArray):
""" An array that have actual storage, whether owned or not
"""
@@ -973,7 +958,7 @@
self._fast_setslice(space, w_value)
else:
arr = SliceArray(self.shape, self.dtype, self, w_value)
- self._sliceloop(arr)
+ loop.compute(arr)
def _fast_setslice(self, space, w_value):
assert isinstance(w_value, ConcreteArray)
@@ -997,17 +982,6 @@
source.next()
dest.next()
- def _sliceloop(self, arr):
- sig = arr.find_sig()
- frame = sig.create_frame(arr)
- shapelen = len(self.shape)
- while not frame.done():
- slice_driver.jit_merge_point(sig=sig, frame=frame, self=self,
- arr=arr,
- shapelen=shapelen)
- sig.eval(frame, arr)
- frame.next(shapelen)
-
def copy(self, space):
array = W_NDimArray(self.size, self.shape[:], self.dtype, self.order)
array.setslice(space, self)
@@ -1033,9 +1007,9 @@
parent.order, parent)
self.start = start
- def create_iter(self):
+ def create_iter(self, transforms=None):
return ViewIterator(self.start, self.strides, self.backstrides,
- self.shape)
+ self.shape).apply_transformations(self, transforms)
def setshape(self, space, new_shape):
if len(self.shape) < 1:
@@ -1084,8 +1058,8 @@
self.shape = new_shape
self.calc_strides(new_shape)
- def create_iter(self):
- return ArrayIterator(self.size)
+ def create_iter(self, transforms=None):
+ return ArrayIterator(self.size).apply_transformations(self, transforms)
def create_sig(self):
return signature.ArraySignature(self.dtype)
@@ -1289,11 +1263,13 @@
BaseArray.descr_set_shape),
size = GetSetProperty(BaseArray.descr_get_size),
ndim = GetSetProperty(BaseArray.descr_get_ndim),
- item = interp2app(BaseArray.descr_item),
+ itemsize = GetSetProperty(BaseArray.descr_get_itemsize),
+ nbytes = GetSetProperty(BaseArray.descr_get_nbytes),
T = GetSetProperty(BaseArray.descr_get_transpose),
flat = GetSetProperty(BaseArray.descr_get_flatiter),
ravel = interp2app(BaseArray.descr_ravel),
+ item = interp2app(BaseArray.descr_item),
mean = interp2app(BaseArray.descr_mean),
sum = interp2app(BaseArray.descr_sum),
@@ -1345,12 +1321,15 @@
def descr_iter(self):
return self
+ def descr_len(self, space):
+ return space.wrap(self.size)
+
def descr_index(self, space):
return space.wrap(self.index)
def descr_coords(self, space):
- coords, step, lngth = to_coords(space, self.base.shape,
- self.base.size, self.base.order,
+ coords, step, lngth = to_coords(space, self.base.shape,
+ self.base.size, self.base.order,
space.wrap(self.index))
return space.newtuple([space.wrap(c) for c in coords])
@@ -1380,7 +1359,7 @@
step=step,
res=res,
ri=ri,
- )
+ )
w_val = base.getitem(basei.offset)
res.setitem(ri.offset,w_val)
basei = basei.next_skip_x(shapelen, step)
@@ -1408,7 +1387,7 @@
arr=arr,
ai=ai,
lngth=lngth,
- )
+ )
v = arr.getitem(ai).convert_to(base.dtype)
base.setitem(basei.offset, v)
# need to repeat input values until all assignments are done
@@ -1419,22 +1398,29 @@
def create_sig(self):
return signature.FlatSignature(self.base.dtype)
+ def create_iter(self, transforms=None):
+ return ViewIterator(self.base.start, self.base.strides,
+ self.base.backstrides,
+ self.base.shape).apply_transformations(self.base,
+ transforms)
+
def descr_base(self, space):
return space.wrap(self.base)
W_FlatIterator.typedef = TypeDef(
'flatiter',
- #__array__ = #MISSING
__iter__ = interp2app(W_FlatIterator.descr_iter),
+ __len__ = interp2app(W_FlatIterator.descr_len),
__getitem__ = interp2app(W_FlatIterator.descr_getitem),
__setitem__ = interp2app(W_FlatIterator.descr_setitem),
+
__eq__ = interp2app(BaseArray.descr_eq),
__ne__ = interp2app(BaseArray.descr_ne),
__lt__ = interp2app(BaseArray.descr_lt),
__le__ = interp2app(BaseArray.descr_le),
__gt__ = interp2app(BaseArray.descr_gt),
__ge__ = interp2app(BaseArray.descr_ge),
- #__sizeof__ #MISSING
+
base = GetSetProperty(W_FlatIterator.descr_base),
index = GetSetProperty(W_FlatIterator.descr_index),
coords = GetSetProperty(W_FlatIterator.descr_coords),
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -2,31 +2,10 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
-from pypy.module.micronumpy import interp_boxes, interp_dtype, support
-from pypy.module.micronumpy.signature import (ReduceSignature, find_sig,
- new_printable_location, AxisReduceSignature, ScalarSignature)
-from pypy.rlib import jit
+from pypy.module.micronumpy import interp_boxes, interp_dtype, support, loop
from pypy.rlib.rarithmetic import LONG_BIT
from pypy.tool.sourcetools import func_with_new_name
-
-reduce_driver = jit.JitDriver(
- greens=['shapelen', "sig"],
- virtualizables=["frame"],
- reds=["frame", "self", "dtype", "value", "obj"],
- get_printable_location=new_printable_location('reduce'),
- name='numpy_reduce',
-)
-
-axisreduce_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['self','arr', 'identity', 'frame'],
- name='numpy_axisreduce',
- get_printable_location=new_printable_location('axisreduce'),
-)
-
-
class W_Ufunc(Wrappable):
_attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
_immutable_fields_ = ["promote_to_float", "promote_bools", "name"]
@@ -140,7 +119,7 @@
def reduce(self, space, w_obj, multidim, promote_to_largest, dim,
keepdims=False):
from pypy.module.micronumpy.interp_numarray import convert_to_array, \
- Scalar
+ Scalar, ReduceArray
if self.argcount != 2:
raise OperationError(space.w_ValueError, space.wrap("reduce only "
"supported for binary functions"))
@@ -151,96 +130,37 @@
if isinstance(obj, Scalar):
raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
"on a scalar"))
-
size = obj.size
- dtype = find_unaryop_result_dtype(
- space, obj.find_dtype(),
- promote_to_float=self.promote_to_float,
- promote_to_largest=promote_to_largest,
- promote_bools=True
- )
+ if self.comparison_func:
+ dtype = interp_dtype.get_dtype_cache(space).w_booldtype
+ else:
+ dtype = find_unaryop_result_dtype(
+ space, obj.find_dtype(),
+ promote_to_float=self.promote_to_float,
+ promote_to_largest=promote_to_largest,
+ promote_bools=True
+ )
shapelen = len(obj.shape)
if self.identity is None and size == 0:
raise operationerrfmt(space.w_ValueError, "zero-size array to "
"%s.reduce without identity", self.name)
if shapelen > 1 and dim >= 0:
- res = self.do_axis_reduce(obj, dtype, dim, keepdims)
- return space.wrap(res)
- scalarsig = ScalarSignature(dtype)
- sig = find_sig(ReduceSignature(self.func, self.name, dtype,
- scalarsig,
- obj.create_sig()), obj)
- frame = sig.create_frame(obj)
- if self.identity is None:
- value = sig.eval(frame, obj).convert_to(dtype)
- frame.next(shapelen)
- else:
- value = self.identity.convert_to(dtype)
- return self.reduce_loop(shapelen, sig, frame, value, obj, dtype)
+ return self.do_axis_reduce(obj, dtype, dim, keepdims)
+ arr = ReduceArray(self.func, self.name, self.identity, obj, dtype)
+ return loop.compute(arr)
def do_axis_reduce(self, obj, dtype, dim, keepdims):
from pypy.module.micronumpy.interp_numarray import AxisReduce,\
W_NDimArray
-
if keepdims:
shape = obj.shape[:dim] + [1] + obj.shape[dim + 1:]
else:
shape = obj.shape[:dim] + obj.shape[dim + 1:]
result = W_NDimArray(support.product(shape), shape, dtype)
- rightsig = obj.create_sig()
- # note - this is just a wrapper so signature can fetch
- # both left and right, nothing more, especially
- # this is not a true virtual array, because shapes
- # don't quite match
- arr = AxisReduce(self.func, self.name, obj.shape, dtype,
+ arr = AxisReduce(self.func, self.name, self.identity, obj.shape, dtype,
result, obj, dim)
- scalarsig = ScalarSignature(dtype)
- sig = find_sig(AxisReduceSignature(self.func, self.name, dtype,
- scalarsig, rightsig), arr)
- assert isinstance(sig, AxisReduceSignature)
- frame = sig.create_frame(arr)
- shapelen = len(obj.shape)
- if self.identity is not None:
- identity = self.identity.convert_to(dtype)
- else:
- identity = None
- self.reduce_axis_loop(frame, sig, shapelen, arr, identity)
- return result
-
- def reduce_axis_loop(self, frame, sig, shapelen, arr, identity):
- # note - we can be advanterous here, depending on the exact field
- # layout. For now let's say we iterate the original way and
- # simply follow the original iteration order
- while not frame.done():
- axisreduce_driver.jit_merge_point(frame=frame, self=self,
- sig=sig,
- identity=identity,
- shapelen=shapelen, arr=arr)
- iterator = frame.get_final_iter()
- v = sig.eval(frame, arr).convert_to(sig.calc_dtype)
- if iterator.first_line:
- if identity is not None:
- value = self.func(sig.calc_dtype, identity, v)
- else:
- value = v
- else:
- cur = arr.left.getitem(iterator.offset)
- value = self.func(sig.calc_dtype, cur, v)
- arr.left.setitem(iterator.offset, value)
- frame.next(shapelen)
-
- def reduce_loop(self, shapelen, sig, frame, value, obj, dtype):
- while not frame.done():
- reduce_driver.jit_merge_point(sig=sig,
- shapelen=shapelen, self=self,
- value=value, obj=obj, frame=frame,
- dtype=dtype)
- assert isinstance(sig, ReduceSignature)
- value = sig.binfunc(dtype, value,
- sig.eval(frame, obj).convert_to(dtype))
- frame.next(shapelen)
- return value
-
+ loop.compute(arr)
+ return arr.left
class W_Ufunc1(W_Ufunc):
argcount = 1
@@ -312,7 +232,6 @@
w_lhs.value.convert_to(calc_dtype),
w_rhs.value.convert_to(calc_dtype)
))
-
new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
w_res = Call2(self.func, self.name,
new_shape, calc_dtype,
@@ -482,6 +401,13 @@
("isnan", "isnan", 1, {"bool_result": True}),
("isinf", "isinf", 1, {"bool_result": True}),
+ ('logical_and', 'logical_and', 2, {'comparison_func': True,
+ 'identity': 1}),
+ ('logical_or', 'logical_or', 2, {'comparison_func': True,
+ 'identity': 0}),
+ ('logical_xor', 'logical_xor', 2, {'comparison_func': True}),
+ ('logical_not', 'logical_not', 1, {'bool_result': True}),
+
("maximum", "max", 2),
("minimum", "min", 2),
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/loop.py
@@ -0,0 +1,83 @@
+
+""" This file is the main run loop as well as evaluation loops for various
+signatures
+"""
+
+from pypy.rlib.jit import JitDriver, hint, unroll_safe, promote
+from pypy.module.micronumpy.interp_iter import ConstantIterator
+
+class NumpyEvalFrame(object):
+ _virtualizable2_ = ['iterators[*]', 'final_iter', 'arraylist[*]',
+ 'value', 'identity', 'cur_value']
+
+ @unroll_safe
+ def __init__(self, iterators, arrays):
+ self = hint(self, access_directly=True, fresh_virtualizable=True)
+ self.iterators = iterators[:]
+ self.arrays = arrays[:]
+ for i in range(len(self.iterators)):
+ iter = self.iterators[i]
+ if not isinstance(iter, ConstantIterator):
+ self.final_iter = i
+ break
+ else:
+ self.final_iter = -1
+ self.cur_value = None
+ self.identity = None
+
+ def done(self):
+ final_iter = promote(self.final_iter)
+ if final_iter < 0:
+ assert False
+ return self.iterators[final_iter].done()
+
+ @unroll_safe
+ def next(self, shapelen):
+ for i in range(len(self.iterators)):
+ self.iterators[i] = self.iterators[i].next(shapelen)
+
+ @unroll_safe
+ def next_from_second(self, shapelen):
+ """ Don't increase the first iterator
+ """
+ for i in range(1, len(self.iterators)):
+ self.iterators[i] = self.iterators[i].next(shapelen)
+
+ def next_first(self, shapelen):
+ self.iterators[0] = self.iterators[0].next(shapelen)
+
+ def get_final_iter(self):
+ final_iter = promote(self.final_iter)
+ if final_iter < 0:
+ assert False
+ return self.iterators[final_iter]
+
+def get_printable_location(shapelen, sig):
+ return 'numpy ' + sig.debug_repr() + ' [%d dims]' % (shapelen,)
+
+numpy_driver = JitDriver(
+ greens=['shapelen', 'sig'],
+ virtualizables=['frame'],
+ reds=['frame', 'arr'],
+ get_printable_location=get_printable_location,
+ name='numpy',
+)
+
+class ComputationDone(Exception):
+ def __init__(self, value):
+ self.value = value
+
+def compute(arr):
+ sig = arr.find_sig()
+ shapelen = len(arr.shape)
+ frame = sig.create_frame(arr)
+ try:
+ while not frame.done():
+ numpy_driver.jit_merge_point(sig=sig,
+ shapelen=shapelen,
+ frame=frame, arr=arr)
+ sig.eval(frame, arr)
+ frame.next(shapelen)
+ return frame.cur_value
+ except ComputationDone, e:
+ return e.value
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -1,9 +1,9 @@
from pypy.rlib.objectmodel import r_dict, compute_identity_hash, compute_hash
from pypy.rlib.rarithmetic import intmask
-from pypy.module.micronumpy.interp_iter import ViewIterator, ArrayIterator, \
- ConstantIterator, AxisIterator, ViewTransform,\
- BroadcastTransform
-from pypy.rlib.jit import hint, unroll_safe, promote
+from pypy.module.micronumpy.interp_iter import ConstantIterator, AxisIterator,\
+ ViewTransform, BroadcastTransform
+from pypy.tool.pairtype import extendabletype
+from pypy.module.micronumpy.loop import ComputationDone
""" Signature specifies both the numpy expression that has been constructed
and the assembler to be compiled. This is a very important observation -
@@ -54,50 +54,6 @@
known_sigs[sig] = sig
return sig
-class NumpyEvalFrame(object):
- _virtualizable2_ = ['iterators[*]', 'final_iter', 'arraylist[*]',
- 'value', 'identity']
-
- @unroll_safe
- def __init__(self, iterators, arrays):
- self = hint(self, access_directly=True, fresh_virtualizable=True)
- self.iterators = iterators[:]
- self.arrays = arrays[:]
- for i in range(len(self.iterators)):
- iter = self.iterators[i]
- if not isinstance(iter, ConstantIterator):
- self.final_iter = i
- break
- else:
- self.final_iter = -1
-
- def done(self):
- final_iter = promote(self.final_iter)
- if final_iter < 0:
- assert False
- return self.iterators[final_iter].done()
-
- @unroll_safe
- def next(self, shapelen):
- for i in range(len(self.iterators)):
- self.iterators[i] = self.iterators[i].next(shapelen)
-
- @unroll_safe
- def next_from_second(self, shapelen):
- """ Don't increase the first iterator
- """
- for i in range(1, len(self.iterators)):
- self.iterators[i] = self.iterators[i].next(shapelen)
-
- def next_first(self, shapelen):
- self.iterators[0] = self.iterators[0].next(shapelen)
-
- def get_final_iter(self):
- final_iter = promote(self.final_iter)
- if final_iter < 0:
- assert False
- return self.iterators[final_iter]
-
def _add_ptr_to_cache(ptr, cache):
i = 0
for p in cache:
@@ -113,6 +69,8 @@
return r_dict(sigeq_no_numbering, sighash)
class Signature(object):
+ __metaclass_ = extendabletype
+
_attrs_ = ['iter_no', 'array_no']
_immutable_fields_ = ['iter_no', 'array_no']
@@ -138,11 +96,15 @@
self.iter_no = no
def create_frame(self, arr):
+ from pypy.module.micronumpy.loop import NumpyEvalFrame
+
iterlist = []
arraylist = []
self._create_iter(iterlist, arraylist, arr, [])
- return NumpyEvalFrame(iterlist, arraylist)
-
+ f = NumpyEvalFrame(iterlist, arraylist)
+ # hook for cur_value being used by reduce
+ arr.compute_first_step(self, f)
+ return f
class ConcreteSignature(Signature):
_immutable_fields_ = ['dtype']
@@ -182,13 +144,10 @@
assert isinstance(concr, ConcreteArray)
storage = concr.storage
if self.iter_no >= len(iterlist):
- iterlist.append(self.allocate_iter(concr, transforms))
+ iterlist.append(concr.create_iter(transforms))
if self.array_no >= len(arraylist):
arraylist.append(storage)
- def allocate_iter(self, arr, transforms):
- return ArrayIterator(arr.size).apply_transformations(arr, transforms)
-
def eval(self, frame, arr):
iter = frame.iterators[self.iter_no]
return self.dtype.getitem(frame.arrays[self.array_no], iter.offset)
@@ -220,22 +179,10 @@
allnumbers.append(no)
self.iter_no = no
- def allocate_iter(self, arr, transforms):
- return ViewIterator(arr.start, arr.strides, arr.backstrides,
- arr.shape).apply_transformations(arr, transforms)
-
class FlatSignature(ViewSignature):
def debug_repr(self):
return 'Flat'
- def allocate_iter(self, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import W_FlatIterator
- assert isinstance(arr, W_FlatIterator)
- return ViewIterator(arr.base.start, arr.base.strides,
- arr.base.backstrides,
- arr.base.shape).apply_transformations(arr.base,
- transforms)
-
class VirtualSliceSignature(Signature):
def __init__(self, child):
self.child = child
@@ -269,12 +216,13 @@
return self.child.eval(frame, arr.child)
class Call1(Signature):
- _immutable_fields_ = ['unfunc', 'name', 'child']
+ _immutable_fields_ = ['unfunc', 'name', 'child', 'dtype']
- def __init__(self, func, name, child):
+ def __init__(self, func, name, dtype, child):
self.unfunc = func
self.child = child
self.name = name
+ self.dtype = dtype
def hash(self):
return compute_hash(self.name) ^ intmask(self.child.hash() << 1)
@@ -359,6 +307,17 @@
return 'Call2(%s, %s, %s)' % (self.name, self.left.debug_repr(),
self.right.debug_repr())
+class ResultSignature(Call2):
+ def __init__(self, dtype, left, right):
+ Call2.__init__(self, None, 'assign', dtype, left, right)
+
+ def eval(self, frame, arr):
+ from pypy.module.micronumpy.interp_numarray import ResultArray
+
+ assert isinstance(arr, ResultArray)
+ offset = frame.get_final_iter().offset
+ arr.left.setitem(offset, self.right.eval(frame, arr.right))
+
class BroadcastLeft(Call2):
def _invent_numbering(self, cache, allnumbers):
self.left._invent_numbering(new_cache(), allnumbers)
@@ -400,20 +359,24 @@
self.right._create_iter(iterlist, arraylist, arr.right, rtransforms)
class ReduceSignature(Call2):
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- self.right._create_iter(iterlist, arraylist, arr, transforms)
-
- def _invent_numbering(self, cache, allnumbers):
- self.right._invent_numbering(cache, allnumbers)
-
- def _invent_array_numbering(self, arr, cache):
- self.right._invent_array_numbering(arr, cache)
-
+ _immutable_fields_ = ['binfunc', 'name', 'calc_dtype',
+ 'left', 'right', 'done_func']
+
+ def __init__(self, func, name, calc_dtype, left, right,
+ done_func):
+ Call2.__init__(self, func, name, calc_dtype, left, right)
+ self.done_func = done_func
+
def eval(self, frame, arr):
- return self.right.eval(frame, arr)
+ from pypy.module.micronumpy.interp_numarray import ReduceArray
+ assert isinstance(arr, ReduceArray)
+ rval = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
+ if self.done_func is not None and self.done_func(self.calc_dtype, rval):
+ raise ComputationDone(rval)
+ frame.cur_value = self.binfunc(self.calc_dtype, frame.cur_value, rval)
def debug_repr(self):
- return 'ReduceSig(%s, %s)' % (self.name, self.right.debug_repr())
+ return 'ReduceSig(%s)' % (self.name, self.right.debug_repr())
class SliceloopSignature(Call2):
def eval(self, frame, arr):
@@ -467,7 +430,17 @@
from pypy.module.micronumpy.interp_numarray import AxisReduce
assert isinstance(arr, AxisReduce)
- return self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
+ iterator = frame.get_final_iter()
+ v = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
+ if iterator.first_line:
+ if frame.identity is not None:
+ value = self.binfunc(self.calc_dtype, frame.identity, v)
+ else:
+ value = v
+ else:
+ cur = arr.left.getitem(iterator.offset)
+ value = self.binfunc(self.calc_dtype, cur, v)
+ arr.left.setitem(iterator.offset, value)
def debug_repr(self):
return 'AxisReduceSig(%s, %s)' % (self.name, self.right.debug_repr())
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -401,3 +401,9 @@
else:
assert issubclass(int64, int)
assert int_ is int64
+
+ def test_operators(self):
+ from operator import truediv
+ from _numpypy import float64, int_
+
+ assert truediv(int_(3), int_(2)) == float64(1.5)
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1,11 +1,13 @@
import py
+
+from pypy.conftest import gettestobjspace, option
+from pypy.interpreter.error import OperationError
+from pypy.module.micronumpy import signature
+from pypy.module.micronumpy.appbridge import get_appbridge_cache
+from pypy.module.micronumpy.interp_iter import Chunk
+from pypy.module.micronumpy.interp_numarray import W_NDimArray, shape_agreement
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
-from pypy.module.micronumpy.interp_numarray import W_NDimArray, shape_agreement
-from pypy.module.micronumpy.interp_iter import Chunk
-from pypy.module.micronumpy import signature
-from pypy.interpreter.error import OperationError
-from pypy.conftest import gettestobjspace
class MockDtype(object):
@@ -173,7 +175,7 @@
def _to_coords(index, order):
return to_coords(self.space, [2, 3, 4], 24, order,
self.space.wrap(index))[0]
-
+
assert _to_coords(0, 'C') == [0, 0, 0]
assert _to_coords(1, 'C') == [0, 0, 1]
assert _to_coords(-1, 'C') == [1, 2, 3]
@@ -306,7 +308,7 @@
from _numpypy import arange
a = arange(15).reshape(3, 5)
assert a[1, 3] == 8
- assert a.T[1, 2] == 11
+ assert a.T[1, 2] == 11
def test_setitem(self):
from _numpypy import array
@@ -936,10 +938,9 @@
[[86, 302, 518], [110, 390, 670], [134, 478, 822]]]).all()
c = dot(a, b[:, 2])
assert (c == [[62, 214, 366], [518, 670, 822]]).all()
- a = arange(3*4*5*6).reshape((3,4,5,6))
- b = arange(3*4*5*6)[::-1].reshape((5,4,6,3))
- assert dot(a, b)[2,3,2,1,2,2] == 499128
- assert sum(a[2,3,2,:] * b[1,2,:,2]) == 499128
+ a = arange(3*2*6).reshape((3,2,6))
+ b = arange(3*2*6)[::-1].reshape((2,6,3))
+ assert dot(a, b)[2,0,1,2] == 1140
def test_dot_constant(self):
from _numpypy import array, dot
@@ -1121,14 +1122,14 @@
f1 = array([0,1])
f = concatenate((f1, [2], f1, [7]))
assert (f == [0,1,2,0,1,7]).all()
-
+
bad_axis = raises(ValueError, concatenate, (a1,a2), axis=1)
assert str(bad_axis.value) == "bad axis argument"
-
+
concat_zero = raises(ValueError, concatenate, ())
assert str(concat_zero.value) == \
"concatenation of zero-length sequences is impossible"
-
+
dims_disagree = raises(ValueError, concatenate, (a1, b1), axis=0)
assert str(dims_disagree.value) == \
"array dimensions must agree except for axis being concatenated"
@@ -1163,6 +1164,25 @@
a = array([[1, 2], [3, 4]])
assert (a.T.flatten() == [1, 3, 2, 4]).all()
+ def test_itemsize(self):
+ from _numpypy import ones, dtype, array
+
+ for obj in [float, bool, int]:
+ assert ones(1, dtype=obj).itemsize == dtype(obj).itemsize
+ assert (ones(1) + ones(1)).itemsize == 8
+ assert array(1.0).itemsize == 8
+ assert ones(1)[:].itemsize == 8
+
+ def test_nbytes(self):
+ from _numpypy import array, ones
+
+ assert ones(1).nbytes == 8
+ assert ones((2, 2)).nbytes == 32
+ assert ones((2, 2))[1:,].nbytes == 16
+ assert (ones(1) + ones(1)).nbytes == 8
+ assert array(3.0).nbytes == 8
+
+
class AppTestMultiDim(BaseNumpyAppTest):
def test_init(self):
import _numpypy
@@ -1458,35 +1478,37 @@
b = a.T.flat
assert (b == [0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11]).all()
assert not (b != [0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11]).any()
- assert ((b >= range(12)) == [True, True, True,False, True, True,
+ assert ((b >= range(12)) == [True, True, True,False, True, True,
False, False, True, False, False, True]).all()
- assert ((b < range(12)) != [True, True, True,False, True, True,
+ assert ((b < range(12)) != [True, True, True,False, True, True,
False, False, True, False, False, True]).all()
- assert ((b <= range(12)) != [False, True, True,False, True, True,
+ assert ((b <= range(12)) != [False, True, True,False, True, True,
False, False, True, False, False, False]).all()
- assert ((b > range(12)) == [False, True, True,False, True, True,
+ assert ((b > range(12)) == [False, True, True,False, True, True,
False, False, True, False, False, False]).all()
def test_flatiter_view(self):
from _numpypy import arange
a = arange(10).reshape(5, 2)
- #no == yet.
- # a[::2].flat == [0, 1, 4, 5, 8, 9]
- isequal = True
- for y,z in zip(a[::2].flat, [0, 1, 4, 5, 8, 9]):
- if y != z:
- isequal = False
- assert isequal == True
+ assert (a[::2].flat == [0, 1, 4, 5, 8, 9]).all()
def test_flatiter_transpose(self):
from _numpypy import arange
- a = arange(10).reshape(2,5).T
+ a = arange(10).reshape(2, 5).T
b = a.flat
assert (b[:5] == [0, 5, 1, 6, 2]).all()
b.next()
b.next()
b.next()
assert b.index == 3
- assert b.coords == (1,1)
+ assert b.coords == (1, 1)
+
+ def test_flatiter_len(self):
+ from _numpypy import arange
+
+ assert len(arange(10).flat) == 10
+ assert len(arange(10).reshape(2, 5).flat) == 10
+ assert len(arange(10)[:2].flat) == 2
+ assert len((arange(2) + arange(2)).flat) == 2
def test_slice_copy(self):
from _numpypy import zeros
@@ -1740,10 +1762,11 @@
assert len(a) == 8
assert arange(False, True, True).dtype is dtype(int)
-from pypy.module.micronumpy.appbridge import get_appbridge_cache
class AppTestRepr(BaseNumpyAppTest):
def setup_class(cls):
+ if option.runappdirect:
+ py.test.skip("Can't be run directly.")
BaseNumpyAppTest.setup_class.im_func(cls)
cache = get_appbridge_cache(cls.space)
cls.old_array_repr = cache.w_array_repr
@@ -1757,6 +1780,8 @@
assert str(array([1, 2, 3])) == 'array([1, 2, 3])'
def teardown_class(cls):
+ if option.runappdirect:
+ return
cache = get_appbridge_cache(cls.space)
cache.w_array_repr = cls.old_array_repr
cache.w_array_str = cls.old_array_str
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -347,8 +347,9 @@
raises((ValueError, TypeError), add.reduce, 1)
def test_reduce_1d(self):
- from _numpypy import add, maximum
+ from _numpypy import add, maximum, less
+ assert less.reduce([5, 4, 3, 2, 1])
assert add.reduce([1, 2, 3]) == 6
assert maximum.reduce([1]) == 1
assert maximum.reduce([1, 2, 3]) == 3
@@ -433,3 +434,14 @@
assert (isnan(array([0.2, float('inf'), float('nan')])) == [False, False, True]).all()
assert (isinf(array([0.2, float('inf'), float('nan')])) == [False, True, False]).all()
assert isinf(array([0.2])).dtype.kind == 'b'
+
+ def test_logical_ops(self):
+ from _numpypy import logical_and, logical_or, logical_xor, logical_not
+
+ assert (logical_and([True, False , True, True], [1, 1, 3, 0])
+ == [True, False, True, False]).all()
+ assert (logical_or([True, False, True, False], [1, 2, 0, 0])
+ == [True, True, True, False]).all()
+ assert (logical_xor([True, False, True, False], [1, 2, 0, 0])
+ == [False, True, True, False]).all()
+ assert (logical_not([True, False]) == [False, True]).all()
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -84,7 +84,7 @@
def test_add(self):
result = self.run("add")
self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
- 'setinteriorfield_raw': 1, 'int_add': 2,
+ 'setinteriorfield_raw': 1, 'int_add': 1,
'int_ge': 1, 'guard_false': 1, 'jump': 1,
'arraylen_gc': 1})
assert result == 3 + 3
@@ -99,7 +99,7 @@
result = self.run("float_add")
assert result == 3 + 3
self.check_simple_loop({"getinteriorfield_raw": 1, "float_add": 1,
- "setinteriorfield_raw": 1, "int_add": 2,
+ "setinteriorfield_raw": 1, "int_add": 1,
"int_ge": 1, "guard_false": 1, "jump": 1,
'arraylen_gc': 1})
@@ -198,7 +198,8 @@
result = self.run("any")
assert result == 1
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
- "float_ne": 1, "int_add": 1,
+ "int_and": 1, "int_add": 1,
+ 'cast_float_to_int': 1,
"int_ge": 1, "jump": 1,
"guard_false": 2, 'arraylen_gc': 1})
@@ -239,7 +240,7 @@
assert result == -6
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
"float_neg": 1,
- "setinteriorfield_raw": 1, "int_add": 2,
+ "setinteriorfield_raw": 1, "int_add": 1,
"int_ge": 1, "guard_false": 1, "jump": 1,
'arraylen_gc': 1})
@@ -321,7 +322,7 @@
# int_add might be 1 here if we try slightly harder with
# reusing indexes or some optimization
self.check_simple_loop({'float_add': 1, 'getinteriorfield_raw': 2,
- 'guard_false': 1, 'int_add': 2, 'int_ge': 1,
+ 'guard_false': 1, 'int_add': 1, 'int_ge': 1,
'jump': 1, 'setinteriorfield_raw': 1,
'arraylen_gc': 1})
@@ -387,7 +388,7 @@
assert result == 4
self.check_trace_count(1)
self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
- 'setinteriorfield_raw': 1, 'int_add': 2,
+ 'setinteriorfield_raw': 1, 'int_add': 1,
'int_ge': 1, 'guard_false': 1, 'jump': 1,
'arraylen_gc': 1})
def define_flat_iter():
@@ -403,7 +404,7 @@
assert result == 6
self.check_trace_count(1)
self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
- 'setinteriorfield_raw': 1, 'int_add': 3,
+ 'setinteriorfield_raw': 1, 'int_add': 2,
'int_ge': 1, 'guard_false': 1,
'arraylen_gc': 1, 'jump': 1})
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -181,6 +181,22 @@
def ge(self, v1, v2):
return v1 >= v2
+ @raw_binary_op
+ def logical_and(self, v1, v2):
+ return bool(v1) and bool(v2)
+
+ @raw_binary_op
+ def logical_or(self, v1, v2):
+ return bool(v1) or bool(v2)
+
+ @raw_unary_op
+ def logical_not(self, v):
+ return not bool(v)
+
+ @raw_binary_op
+ def logical_xor(self, v1, v2):
+ return bool(v1) ^ bool(v2)
+
def bool(self, v):
return bool(self.for_computation(self.unbox(v)))
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -37,7 +37,7 @@
if space.isinstance_w(w_obj, space.w_unicode):
w_obj = space.call_method(w_obj, 'encode',
getfilesystemencoding(space))
- return space.str_w(w_obj)
+ return space.str0_w(w_obj)
class FileEncoder(object):
def __init__(self, space, w_obj):
@@ -48,7 +48,7 @@
return fsencode_w(self.space, self.w_obj)
def as_unicode(self):
- return self.space.unicode_w(self.w_obj)
+ return self.space.unicode0_w(self.w_obj)
class FileDecoder(object):
def __init__(self, space, w_obj):
@@ -56,13 +56,13 @@
self.w_obj = w_obj
def as_bytes(self):
- return self.space.str_w(self.w_obj)
+ return self.space.str0_w(self.w_obj)
def as_unicode(self):
space = self.space
w_unicode = space.call_method(self.w_obj, 'decode',
getfilesystemencoding(space))
- return space.unicode_w(w_unicode)
+ return space.unicode0_w(w_unicode)
@specialize.memo()
def dispatch_filename(func, tag=0):
@@ -71,7 +71,7 @@
fname = FileEncoder(space, w_fname)
return func(fname, *args)
else:
- fname = space.str_w(w_fname)
+ fname = space.str0_w(w_fname)
return func(fname, *args)
return dispatch
@@ -369,7 +369,7 @@
space.wrap(times[3]),
space.wrap(times[4])])
- at unwrap_spec(cmd=str)
+ at unwrap_spec(cmd='str0')
def system(space, cmd):
"""Execute the command (a string) in a subshell."""
try:
@@ -401,7 +401,7 @@
fullpath = rposix._getfullpathname(path)
w_fullpath = space.wrap(fullpath)
else:
- path = space.str_w(w_path)
+ path = space.str0_w(w_path)
fullpath = rposix._getfullpathname(path)
w_fullpath = space.wrap(fullpath)
except OSError, e:
@@ -512,7 +512,7 @@
for key, value in os.environ.items():
space.setitem(w_env, space.wrap(key), space.wrap(value))
- at unwrap_spec(name=str, value=str)
+ at unwrap_spec(name='str0', value='str0')
def putenv(space, name, value):
"""Change or add an environment variable."""
try:
@@ -520,7 +520,7 @@
except OSError, e:
raise wrap_oserror(space, e)
- at unwrap_spec(name=str)
+ at unwrap_spec(name='str0')
def unsetenv(space, name):
"""Delete an environment variable."""
try:
@@ -548,7 +548,7 @@
for s in result
]
else:
- dirname = space.str_w(w_dirname)
+ dirname = space.str0_w(w_dirname)
result = rposix.listdir(dirname)
result_w = [space.wrap(s) for s in result]
except OSError, e:
@@ -635,7 +635,7 @@
import signal
os.kill(os.getpid(), signal.SIGABRT)
- at unwrap_spec(src=str, dst=str)
+ at unwrap_spec(src='str0', dst='str0')
def link(space, src, dst):
"Create a hard link to a file."
try:
@@ -650,7 +650,7 @@
except OSError, e:
raise wrap_oserror(space, e)
- at unwrap_spec(path=str)
+ at unwrap_spec(path='str0')
def readlink(space, path):
"Return a string representing the path to which the symbolic link points."
try:
@@ -765,7 +765,7 @@
w_keys = space.call_method(w_env, 'keys')
for w_key in space.unpackiterable(w_keys):
w_value = space.getitem(w_env, w_key)
- env[space.str_w(w_key)] = space.str_w(w_value)
+ env[space.str0_w(w_key)] = space.str0_w(w_value)
return env
def execve(space, w_command, w_args, w_env):
@@ -785,18 +785,18 @@
except OSError, e:
raise wrap_oserror(space, e)
- at unwrap_spec(mode=int, path=str)
+ at unwrap_spec(mode=int, path='str0')
def spawnv(space, mode, path, w_args):
- args = [space.str_w(w_arg) for w_arg in space.unpackiterable(w_args)]
+ args = [space.str0_w(w_arg) for w_arg in space.unpackiterable(w_args)]
try:
ret = os.spawnv(mode, path, args)
except OSError, e:
raise wrap_oserror(space, e)
return space.wrap(ret)
- at unwrap_spec(mode=int, path=str)
+ at unwrap_spec(mode=int, path='str0')
def spawnve(space, mode, path, w_args, w_env):
- args = [space.str_w(w_arg) for w_arg in space.unpackiterable(w_args)]
+ args = [space.str0_w(w_arg) for w_arg in space.unpackiterable(w_args)]
env = _env2interp(space, w_env)
try:
ret = os.spawnve(mode, path, args, env)
@@ -914,7 +914,7 @@
raise wrap_oserror(space, e)
return space.w_None
- at unwrap_spec(path=str)
+ at unwrap_spec(path='str0')
def chroot(space, path):
""" chroot(path)
@@ -1103,7 +1103,7 @@
except OSError, e:
raise wrap_oserror(space, e)
- at unwrap_spec(path=str, uid=c_uid_t, gid=c_gid_t)
+ at unwrap_spec(path='str0', uid=c_uid_t, gid=c_gid_t)
def chown(space, path, uid, gid):
check_uid_range(space, uid)
check_uid_range(space, gid)
@@ -1113,7 +1113,7 @@
raise wrap_oserror(space, e, path)
return space.w_None
- at unwrap_spec(path=str, uid=c_uid_t, gid=c_gid_t)
+ at unwrap_spec(path='str0', uid=c_uid_t, gid=c_gid_t)
def lchown(space, path, uid, gid):
check_uid_range(space, uid)
check_uid_range(space, gid)
diff --git a/pypy/module/posix/test/test_ztranslation.py b/pypy/module/posix/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/posix/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test_posix_translates():
+ checkmodule('posix')
\ No newline at end of file
diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -127,6 +127,7 @@
l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op),
logops.repr_of_resop(op),
jd_sd.jitdriver.name,
+ op.getarg(1).getint(),
w_greenkey))
else:
l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs,
@@ -163,14 +164,14 @@
llres = res.llbox
return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr)
- at unwrap_spec(repr=str, jd_name=str)
-def descr_new_dmp(space, w_tp, w_args, repr, jd_name, w_greenkey):
+ at unwrap_spec(repr=str, jd_name=str, call_depth=int)
+def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, w_greenkey):
args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in
space.listview(w_args)]
num = rop.DEBUG_MERGE_POINT
return DebugMergePoint(space,
jit_hooks.resop_new(num, args, jit_hooks.emptyval()),
- repr, jd_name, w_greenkey)
+ repr, jd_name, call_depth, w_greenkey)
class WrappedOp(Wrappable):
""" A class representing a single ResOperation, wrapped nicely
@@ -205,10 +206,11 @@
jit_hooks.resop_setresult(self.op, box.llbox)
class DebugMergePoint(WrappedOp):
- def __init__(self, space, op, repr_of_resop, jd_name, w_greenkey):
+ def __init__(self, space, op, repr_of_resop, jd_name, call_depth, w_greenkey):
WrappedOp.__init__(self, op, -1, repr_of_resop)
+ self.jd_name = jd_name
+ self.call_depth = call_depth
self.w_greenkey = w_greenkey
- self.jd_name = jd_name
def get_pycode(self, space):
if self.jd_name == pypyjitdriver.name:
@@ -243,6 +245,7 @@
greenkey = interp_attrproperty_w("w_greenkey", cls=DebugMergePoint),
pycode = GetSetProperty(DebugMergePoint.get_pycode),
bytecode_no = GetSetProperty(DebugMergePoint.get_bytecode_no),
+ call_depth = interp_attrproperty("call_depth", cls=DebugMergePoint),
jitdriver_name = GetSetProperty(DebugMergePoint.get_jitdriver_name),
)
DebugMergePoint.acceptable_as_base_class = False
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
--- a/pypy/module/pypyjit/test/test_jit_hook.py
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -122,7 +122,8 @@
assert isinstance(dmp, pypyjit.DebugMergePoint)
assert dmp.pycode is self.f.func_code
assert dmp.greenkey == (self.f.func_code, 0, False)
- #assert int_add.name == 'int_add'
+ assert dmp.call_depth == 0
+ assert int_add.name == 'int_add'
assert int_add.num == self.int_add_num
self.on_compile_bridge()
assert len(all) == 2
@@ -223,11 +224,13 @@
def f():
pass
- op = DebugMergePoint([Box(0)], 'repr', 'pypyjit', (f.func_code, 0, 0))
+ op = DebugMergePoint([Box(0)], 'repr', 'pypyjit', 2, (f.func_code, 0, 0))
assert op.bytecode_no == 0
assert op.pycode is f.func_code
assert repr(op) == 'repr'
assert op.jitdriver_name == 'pypyjit'
assert op.num == self.dmp_num
- op = DebugMergePoint([Box(0)], 'repr', 'notmain', ('str',))
+ assert op.call_depth == 2
+ op = DebugMergePoint([Box(0)], 'repr', 'notmain', 5, ('str',))
raises(AttributeError, 'op.pycode')
+ assert op.call_depth == 5
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -27,6 +27,7 @@
...
p53 = call_assembler(..., descr=...)
guard_not_forced(descr=...)
+ keepalive(...)
guard_no_exception(descr=...)
...
""")
diff --git a/pypy/module/select/__init__.py b/pypy/module/select/__init__.py
--- a/pypy/module/select/__init__.py
+++ b/pypy/module/select/__init__.py
@@ -1,7 +1,6 @@
# Package initialisation
from pypy.interpreter.mixedmodule import MixedModule
-import select
import sys
@@ -15,18 +14,13 @@
'error' : 'space.fromcache(interp_select.Cache).w_error'
}
- # TODO: this doesn't feel right...
- if hasattr(select, "epoll"):
+ if sys.platform.startswith('linux'):
interpleveldefs['epoll'] = 'interp_epoll.W_Epoll'
- symbols = [
- "EPOLLIN", "EPOLLOUT", "EPOLLPRI", "EPOLLERR", "EPOLLHUP",
- "EPOLLET", "EPOLLONESHOT", "EPOLLRDNORM", "EPOLLRDBAND",
- "EPOLLWRNORM", "EPOLLWRBAND", "EPOLLMSG"
- ]
- for symbol in symbols:
- if hasattr(select, symbol):
- interpleveldefs[symbol] = "space.wrap(%s)" % getattr(select, symbol)
-
+ from pypy.module.select.interp_epoll import cconfig, public_symbols
+ for symbol in public_symbols:
+ value = cconfig[symbol]
+ if value is not None:
+ interpleveldefs[symbol] = "space.wrap(%r)" % value
def buildloaders(cls):
from pypy.rlib import rpoll
diff --git a/pypy/module/select/interp_epoll.py b/pypy/module/select/interp_epoll.py
--- a/pypy/module/select/interp_epoll.py
+++ b/pypy/module/select/interp_epoll.py
@@ -29,8 +29,16 @@
("data", CConfig.epoll_data)
])
+public_symbols = [
+ "EPOLLIN", "EPOLLOUT", "EPOLLPRI", "EPOLLERR", "EPOLLHUP",
+ "EPOLLET", "EPOLLONESHOT", "EPOLLRDNORM", "EPOLLRDBAND",
+ "EPOLLWRNORM", "EPOLLWRBAND", "EPOLLMSG"
+ ]
+for symbol in public_symbols:
+ setattr(CConfig, symbol, rffi_platform.DefinedConstantInteger(symbol))
+
for symbol in ["EPOLL_CTL_ADD", "EPOLL_CTL_MOD", "EPOLL_CTL_DEL"]:
- setattr(CConfig, symbol, rffi_platform.DefinedConstantInteger(symbol))
+ setattr(CConfig, symbol, rffi_platform.ConstantInteger(symbol))
cconfig = rffi_platform.configure(CConfig)
diff --git a/pypy/module/select/test/test_epoll.py b/pypy/module/select/test/test_epoll.py
--- a/pypy/module/select/test/test_epoll.py
+++ b/pypy/module/select/test/test_epoll.py
@@ -1,23 +1,17 @@
import py
+import sys
from pypy.conftest import gettestobjspace
class AppTestEpoll(object):
def setup_class(cls):
+ # NB. we should ideally py.test.skip() if running on an old linux
+ # where the kernel doesn't support epoll()
+ if not sys.platform.startswith('linux'):
+ py.test.skip("test requires linux (assumed >= 2.6)")
cls.space = gettestobjspace(usemodules=["select", "_socket", "posix"])
- import errno
- import select
-
- if not hasattr(select, "epoll"):
- py.test.skip("test requires linux 2.6")
- try:
- select.epoll()
- except IOError, e:
- if e.errno == errno.ENOSYS:
- py.test.skip("kernel doesn't support epoll()")
-
def setup_method(self, meth):
self.w_sockets = self.space.wrap([])
diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py
--- a/pypy/module/sys/state.py
+++ b/pypy/module/sys/state.py
@@ -74,7 +74,7 @@
#
return importlist
- at unwrap_spec(srcdir=str)
+ at unwrap_spec(srcdir='str0')
def pypy_initial_path(space, srcdir):
try:
path = getinitialpath(get(space), srcdir)
diff --git a/pypy/module/zipimport/interp_zipimport.py b/pypy/module/zipimport/interp_zipimport.py
--- a/pypy/module/zipimport/interp_zipimport.py
+++ b/pypy/module/zipimport/interp_zipimport.py
@@ -123,7 +123,9 @@
self.prefix = prefix
def getprefix(self, space):
- return space.wrap(self.prefix)
+ if ZIPSEP == os.path.sep:
+ return space.wrap(self.prefix)
+ return space.wrap(self.prefix.replace(ZIPSEP, os.path.sep))
def _find_relative_path(self, filename):
if filename.startswith(self.filename):
@@ -342,7 +344,7 @@
space = self.space
return space.wrap(self.filename)
- at unwrap_spec(name=str)
+ at unwrap_spec(name='str0')
def descr_new_zipimporter(space, w_type, name):
w = space.wrap
ok = False
@@ -381,7 +383,7 @@
prefix = name[len(filename):]
if prefix.startswith(os.path.sep) or prefix.startswith(ZIPSEP):
prefix = prefix[1:]
- if prefix and not prefix.endswith(ZIPSEP):
+ if prefix and not prefix.endswith(ZIPSEP) and not prefix.endswith(os.path.sep):
prefix += ZIPSEP
w_result = space.wrap(W_ZipImporter(space, name, filename, zip_file, prefix))
zip_cache.set(filename, w_result)
diff --git a/pypy/module/zipimport/test/test_undocumented.py b/pypy/module/zipimport/test/test_undocumented.py
--- a/pypy/module/zipimport/test/test_undocumented.py
+++ b/pypy/module/zipimport/test/test_undocumented.py
@@ -119,7 +119,7 @@
zip_importer = zipimport.zipimporter(path)
assert isinstance(zip_importer, zipimport.zipimporter)
assert zip_importer.archive == zip_path
- assert zip_importer.prefix == prefix
+ assert zip_importer.prefix == prefix.replace('/', os.path.sep)
assert zip_path in zipimport._zip_directory_cache
finally:
self.cleanup_zipfile(self.created_paths)
diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py
--- a/pypy/module/zipimport/test/test_zipimport.py
+++ b/pypy/module/zipimport/test/test_zipimport.py
@@ -15,7 +15,7 @@
cpy's regression tests
"""
compression = ZIP_STORED
- pathsep = '/'
+ pathsep = os.path.sep
def make_pyc(cls, space, co, mtime):
data = marshal.dumps(co)
@@ -129,7 +129,7 @@
self.writefile('sub/__init__.py', '')
self.writefile('sub/yy.py', '')
from zipimport import _zip_directory_cache, zipimporter
- sub_importer = zipimporter(self.zipfile + '/sub')
+ sub_importer = zipimporter(self.zipfile + os.path.sep + 'sub')
main_importer = zipimporter(self.zipfile)
assert main_importer is not sub_importer
diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py
--- a/pypy/rlib/ropenssl.py
+++ b/pypy/rlib/ropenssl.py
@@ -54,6 +54,7 @@
ASN1_STRING = lltype.Ptr(lltype.ForwardReference())
ASN1_ITEM = rffi.COpaquePtr('ASN1_ITEM')
+ASN1_ITEM_EXP = lltype.Ptr(lltype.FuncType([], ASN1_ITEM))
X509_NAME = rffi.COpaquePtr('X509_NAME')
class CConfig:
@@ -101,12 +102,11 @@
X509_extension_st = rffi_platform.Struct(
'struct X509_extension_st',
[('value', ASN1_STRING)])
- ASN1_ITEM_EXP = lltype.FuncType([], ASN1_ITEM)
X509V3_EXT_D2I = lltype.FuncType([rffi.VOIDP, rffi.CCHARPP, rffi.LONG],
rffi.VOIDP)
v3_ext_method = rffi_platform.Struct(
'struct v3_ext_method',
- [('it', lltype.Ptr(ASN1_ITEM_EXP)),
+ [('it', ASN1_ITEM_EXP),
('d2i', lltype.Ptr(X509V3_EXT_D2I))])
GENERAL_NAME_st = rffi_platform.Struct(
'struct GENERAL_NAME_st',
@@ -118,6 +118,8 @@
('block_size', rffi.INT)])
EVP_MD_SIZE = rffi_platform.SizeOf('EVP_MD')
EVP_MD_CTX_SIZE = rffi_platform.SizeOf('EVP_MD_CTX')
+ OPENSSL_EXPORT_VAR_AS_FUNCTION = rffi_platform.Defined(
+ "OPENSSL_EXPORT_VAR_AS_FUNCTION")
for k, v in rffi_platform.configure(CConfig).items():
@@ -224,7 +226,10 @@
ssl_external('i2a_ASN1_INTEGER', [BIO, ASN1_INTEGER], rffi.INT)
ssl_external('ASN1_item_d2i',
[rffi.VOIDP, rffi.CCHARPP, rffi.LONG, ASN1_ITEM], rffi.VOIDP)
-ssl_external('ASN1_ITEM_ptr', [rffi.VOIDP], ASN1_ITEM, macro=True)
+if OPENSSL_EXPORT_VAR_AS_FUNCTION:
+ ssl_external('ASN1_ITEM_ptr', [ASN1_ITEM_EXP], ASN1_ITEM, macro=True)
+else:
+ ssl_external('ASN1_ITEM_ptr', [rffi.VOIDP], ASN1_ITEM, macro=True)
ssl_external('sk_GENERAL_NAME_num', [GENERAL_NAMES], rffi.INT,
macro=True)
diff --git a/pypy/rlib/rstring.py b/pypy/rlib/rstring.py
--- a/pypy/rlib/rstring.py
+++ b/pypy/rlib/rstring.py
@@ -205,3 +205,45 @@
assert p.const is None
return SomeUnicodeBuilder(can_be_None=True)
+#___________________________________________________________________
+# Support functions for SomeString.no_nul
+
+def assert_str0(fname):
+ assert '\x00' not in fname, "NUL byte in string"
+ return fname
+
+class Entry(ExtRegistryEntry):
+ _about_ = assert_str0
+
+ def compute_result_annotation(self, s_obj):
+ if s_None.contains(s_obj):
+ return s_obj
+ assert isinstance(s_obj, (SomeString, SomeUnicodeString))
+ if s_obj.no_nul:
+ return s_obj
+ new_s_obj = SomeObject.__new__(s_obj.__class__)
+ new_s_obj.__dict__ = s_obj.__dict__.copy()
+ new_s_obj.no_nul = True
+ return new_s_obj
+
+ def specialize_call(self, hop):
+ hop.exception_cannot_occur()
+ return hop.inputarg(hop.args_r[0], arg=0)
+
+def check_str0(fname):
+ """A 'probe' to trigger a failure at translation time, if the
+ string was not proved to not contain NUL characters."""
+ assert '\x00' not in fname, "NUL byte in string"
+
+class Entry(ExtRegistryEntry):
+ _about_ = check_str0
+
+ def compute_result_annotation(self, s_obj):
+ if not isinstance(s_obj, (SomeString, SomeUnicodeString)):
+ return s_obj
+ if not s_obj.no_nul:
+ raise ValueError("Value is not no_nul")
+
+ def specialize_call(self, hop):
+ pass
+
diff --git a/pypy/rlib/test/test_rmarshal.py b/pypy/rlib/test/test_rmarshal.py
--- a/pypy/rlib/test/test_rmarshal.py
+++ b/pypy/rlib/test/test_rmarshal.py
@@ -169,7 +169,7 @@
assert st2.st_mode == st.st_mode
assert st2[9] == st[9]
return buf
- fn = compile(f, [str])
+ fn = compile(f, [annmodel.s_Str0])
res = fn('.')
st = os.stat('.')
sttuple = marshal.loads(res)
diff --git a/pypy/rpython/extfunc.py b/pypy/rpython/extfunc.py
--- a/pypy/rpython/extfunc.py
+++ b/pypy/rpython/extfunc.py
@@ -2,7 +2,7 @@
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.rpython.lltypesystem.lltype import typeOf
from pypy.objspace.flow.model import Constant
-from pypy.annotation.model import unionof
+from pypy.annotation import model as annmodel
from pypy.annotation.signature import annotation
import py, sys
@@ -138,7 +138,6 @@
# we defer a bit annotation here
def compute_result_annotation(self):
- from pypy.annotation import model as annmodel
return annmodel.SomeGenericCallable([annotation(i, self.bookkeeper)
for i in self.instance.args],
annotation(self.instance.result, self.bookkeeper))
@@ -152,8 +151,9 @@
signature_args = [annotation(arg, None) for arg in args]
assert len(args_s) == len(signature_args),\
"Argument number mismatch"
+
for i, expected in enumerate(signature_args):
- arg = unionof(args_s[i], expected)
+ arg = annmodel.unionof(args_s[i], expected)
if not expected.contains(arg):
name = getattr(self, 'name', None)
if not name:
diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py
--- a/pypy/rpython/extfuncregistry.py
+++ b/pypy/rpython/extfuncregistry.py
@@ -85,7 +85,8 @@
# llinterpreter
path_functions = [
- ('join', [str, str], str),
+ ('join', [ll_os.str0, ll_os.str0], ll_os.str0),
+ ('dirname', [ll_os.str0], ll_os.str0),
]
for name, args, res in path_functions:
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -1036,13 +1036,8 @@
libraries = eci.testonly_libraries + eci.libraries + eci.frameworks
FUNCTYPE = lltype.typeOf(funcptr).TO
- if not libraries:
- cfunc = get_on_lib(standard_c_lib, funcname)
- # XXX magic: on Windows try to load the function from 'kernel32' too
- if cfunc is None and hasattr(ctypes, 'windll'):
- cfunc = get_on_lib(ctypes.windll.kernel32, funcname)
- else:
- cfunc = None
+ cfunc = None
+ if libraries:
not_found = []
for libname in libraries:
libpath = None
@@ -1075,6 +1070,12 @@
not_found.append(libname)
if cfunc is None:
+ cfunc = get_on_lib(standard_c_lib, funcname)
+ # XXX magic: on Windows try to load the function from 'kernel32' too
+ if cfunc is None and hasattr(ctypes, 'windll'):
+ cfunc = get_on_lib(ctypes.windll.kernel32, funcname)
+
+ if cfunc is None:
# function name not found in any of the libraries
if not libraries:
place = 'the standard C library (missing libraries=...?)'
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -15,7 +15,7 @@
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rpython.annlowlevel import llhelper
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.rstring import StringBuilder, UnicodeBuilder
+from pypy.rlib.rstring import StringBuilder, UnicodeBuilder, assert_str0
from pypy.rlib import jit
from pypy.rpython.lltypesystem import llmemory
import os, sys
@@ -698,7 +698,7 @@
while cp[i] != lastchar:
b.append(cp[i])
i += 1
- return b.build()
+ return assert_str0(b.build())
# str -> char*
# Can't inline this because of the raw address manipulation.
@@ -804,7 +804,7 @@
while i < maxlen and cp[i] != lastchar:
b.append(cp[i])
i += 1
- return b.build()
+ return assert_str0(b.build())
# char* and size -> str (which can contain null bytes)
def charpsize2str(cp, size):
@@ -842,6 +842,7 @@
array[i] = str2charp(l[i])
array[len(l)] = lltype.nullptr(CCHARP.TO)
return array
+liststr2charpp._annenforceargs_ = [[annmodel.s_Str0]] # List of strings
def free_charpp(ref):
""" frees list of char**, NULL terminated
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -31,6 +31,10 @@
from pypy.rlib import rgc
from pypy.rlib.objectmodel import specialize
+str0 = SomeString(no_nul=True)
+unicode0 = SomeUnicodeString(no_nul=True)
+
+
def monkeypatch_rposix(posixfunc, unicodefunc, signature):
func_name = posixfunc.__name__
@@ -39,12 +43,15 @@
arglist = ['arg%d' % (i,) for i in range(len(signature))]
transformed_arglist = arglist[:]
for i, arg in enumerate(signature):
- if arg is unicode:
+ if arg in (unicode, unicode0):
transformed_arglist[i] = transformed_arglist[i] + '.as_unicode()'
args = ', '.join(arglist)
transformed_args = ', '.join(transformed_arglist)
- main_arg = 'arg%d' % (signature.index(unicode),)
+ try:
+ main_arg = 'arg%d' % (signature.index(unicode0),)
+ except ValueError:
+ main_arg = 'arg%d' % (signature.index(unicode),)
source = py.code.Source("""
def %(func_name)s(%(args)s):
@@ -60,7 +67,7 @@
exec source.compile() in miniglobals
new_func = miniglobals[func_name]
specialized_args = [i for i in range(len(signature))
- if signature[i] in (unicode, None)]
+ if signature[i] in (unicode, unicode0, None)]
new_func = specialize.argtype(*specialized_args)(new_func)
# Monkeypatch the function in pypy.rlib.rposix
@@ -68,6 +75,7 @@
class StringTraits:
str = str
+ str0 = str0
CHAR = rffi.CHAR
CCHARP = rffi.CCHARP
charp2str = staticmethod(rffi.charp2str)
@@ -85,6 +93,7 @@
class UnicodeTraits:
str = unicode
+ str0 = unicode0
CHAR = rffi.WCHAR_T
CCHARP = rffi.CWCHARP
charp2str = staticmethod(rffi.wcharp2unicode)
@@ -301,7 +310,7 @@
rffi.free_charpp(l_args)
raise OSError(rposix.get_errno(), "execv failed")
- return extdef([str, [str]], s_ImpossibleValue, llimpl=execv_llimpl,
+ return extdef([str0, [str0]], s_ImpossibleValue, llimpl=execv_llimpl,
export_name="ll_os.ll_os_execv")
@@ -319,7 +328,8 @@
# appropriate
envstrs = []
for item in env.iteritems():
- envstrs.append("%s=%s" % item)
+ envstr = "%s=%s" % item
+ envstrs.append(envstr)
l_args = rffi.liststr2charpp(args)
l_env = rffi.liststr2charpp(envstrs)
@@ -332,7 +342,7 @@
raise OSError(rposix.get_errno(), "execve failed")
return extdef(
- [str, [str], {str: str}],
+ [str0, [str0], {str0: str0}],
s_ImpossibleValue,
llimpl=execve_llimpl,
export_name="ll_os.ll_os_execve")
@@ -353,7 +363,7 @@
raise OSError(rposix.get_errno(), "os_spawnv failed")
return rffi.cast(lltype.Signed, childpid)
- return extdef([int, str, [str]], int, llimpl=spawnv_llimpl,
+ return extdef([int, str0, [str0]], int, llimpl=spawnv_llimpl,
export_name="ll_os.ll_os_spawnv")
@registering_if(os, 'spawnve')
@@ -378,7 +388,7 @@
raise OSError(rposix.get_errno(), "os_spawnve failed")
return rffi.cast(lltype.Signed, childpid)
- return extdef([int, str, [str], {str: str}], int,
+ return extdef([int, str0, [str0], {str0: str0}], int,
llimpl=spawnve_llimpl,
export_name="ll_os.ll_os_spawnve")
@@ -517,7 +527,7 @@
else:
raise Exception("os.utime() arg 2 must be None or a tuple of "
"2 floats, got %s" % (s_times,))
- os_utime_normalize_args._default_signature_ = [traits.str, None]
+ os_utime_normalize_args._default_signature_ = [traits.str0, None]
return extdef(os_utime_normalize_args, s_None,
"ll_os.ll_os_utime",
@@ -612,7 +622,7 @@
if result == -1:
raise OSError(rposix.get_errno(), "os_chroot failed")
- return extdef([str], None, export_name="ll_os.ll_os_chroot",
+ return extdef([str0], None, export_name="ll_os.ll_os_chroot",
llimpl=chroot_llimpl)
@registering_if(os, 'uname')
@@ -816,7 +826,7 @@
def os_open_oofakeimpl(path, flags, mode):
return os.open(OOSupport.from_rstr(path), flags, mode)
- return extdef([traits.str, int, int], int, traits.ll_os_name('open'),
+ return extdef([traits.str0, int, int], int, traits.ll_os_name('open'),
llimpl=os_open_llimpl, oofakeimpl=os_open_oofakeimpl)
@registering_if(os, 'getloadavg')
@@ -1050,7 +1060,7 @@
def os_access_oofakeimpl(path, mode):
return os.access(OOSupport.from_rstr(path), mode)
- return extdef([traits.str, int], s_Bool, llimpl=access_llimpl,
+ return extdef([traits.str0, int], s_Bool, llimpl=access_llimpl,
export_name=traits.ll_os_name("access"),
oofakeimpl=os_access_oofakeimpl)
@@ -1062,8 +1072,8 @@
from pypy.rpython.module.ll_win32file import make_getfullpathname_impl
getfullpathname_llimpl = make_getfullpathname_impl(traits)
- return extdef([traits.str], # a single argument which is a str
- traits.str, # returns a string
+ return extdef([traits.str0], # a single argument which is a str
+ traits.str0, # returns a string
traits.ll_os_name('_getfullpathname'),
llimpl=getfullpathname_llimpl)
@@ -1174,8 +1184,8 @@
raise OSError(error, "os_readdir failed")
return result
- return extdef([traits.str], # a single argument which is a str
- [traits.str], # returns a list of strings
+ return extdef([traits.str0], # a single argument which is a str
+ [traits.str0], # returns a list of strings
traits.ll_os_name('listdir'),
llimpl=os_listdir_llimpl)
@@ -1241,7 +1251,7 @@
if res == -1:
raise OSError(rposix.get_errno(), "os_chown failed")
- return extdef([str, int, int], None, "ll_os.ll_os_chown",
+ return extdef([str0, int, int], None, "ll_os.ll_os_chown",
llimpl=os_chown_llimpl)
@registering_if(os, 'lchown')
@@ -1254,7 +1264,7 @@
if res == -1:
raise OSError(rposix.get_errno(), "os_lchown failed")
- return extdef([str, int, int], None, "ll_os.ll_os_lchown",
+ return extdef([str0, int, int], None, "ll_os.ll_os_lchown",
llimpl=os_lchown_llimpl)
@registering_if(os, 'readlink')
@@ -1283,12 +1293,11 @@
lltype.free(buf, flavor='raw')
bufsize *= 4
# convert the result to a string
- l = [buf[i] for i in range(res)]
- result = ''.join(l)
+ result = rffi.charp2strn(buf, res)
lltype.free(buf, flavor='raw')
return result
- return extdef([str], str,
+ return extdef([str0], str0,
"ll_os.ll_os_readlink",
llimpl=os_readlink_llimpl)
@@ -1361,7 +1370,7 @@
res = os_system(command)
return rffi.cast(lltype.Signed, res)
- return extdef([str], int, llimpl=system_llimpl,
+ return extdef([str0], int, llimpl=system_llimpl,
export_name="ll_os.ll_os_system")
@registering_str_unicode(os.unlink)
@@ -1383,7 +1392,7 @@
if not win32traits.DeleteFile(path):
raise rwin32.lastWindowsError()
- return extdef([traits.str], s_None, llimpl=unlink_llimpl,
+ return extdef([traits.str0], s_None, llimpl=unlink_llimpl,
export_name=traits.ll_os_name('unlink'))
@registering_str_unicode(os.chdir)
@@ -1401,7 +1410,7 @@
from pypy.rpython.module.ll_win32file import make_chdir_impl
os_chdir_llimpl = make_chdir_impl(traits)
- return extdef([traits.str], s_None, llimpl=os_chdir_llimpl,
+ return extdef([traits.str0], s_None, llimpl=os_chdir_llimpl,
export_name=traits.ll_os_name('chdir'))
@registering_str_unicode(os.mkdir)
@@ -1424,7 +1433,7 @@
if res < 0:
raise OSError(rposix.get_errno(), "os_mkdir failed")
- return extdef([traits.str, int], s_None, llimpl=os_mkdir_llimpl,
+ return extdef([traits.str0, int], s_None, llimpl=os_mkdir_llimpl,
export_name=traits.ll_os_name('mkdir'))
@registering_str_unicode(os.rmdir)
@@ -1437,7 +1446,7 @@
if res < 0:
raise OSError(rposix.get_errno(), "os_rmdir failed")
- return extdef([traits.str], s_None, llimpl=rmdir_llimpl,
+ return extdef([traits.str0], s_None, llimpl=rmdir_llimpl,
export_name=traits.ll_os_name('rmdir'))
@registering_str_unicode(os.chmod)
@@ -1454,7 +1463,7 @@
from pypy.rpython.module.ll_win32file import make_chmod_impl
chmod_llimpl = make_chmod_impl(traits)
- return extdef([traits.str, int], s_None, llimpl=chmod_llimpl,
+ return extdef([traits.str0, int], s_None, llimpl=chmod_llimpl,
export_name=traits.ll_os_name('chmod'))
@registering_str_unicode(os.rename)
@@ -1476,7 +1485,7 @@
if not win32traits.MoveFile(oldpath, newpath):
raise rwin32.lastWindowsError()
- return extdef([traits.str, traits.str], s_None, llimpl=rename_llimpl,
+ return extdef([traits.str0, traits.str0], s_None, llimpl=rename_llimpl,
export_name=traits.ll_os_name('rename'))
@registering_str_unicode(getattr(os, 'mkfifo', None))
@@ -1489,7 +1498,7 @@
if res < 0:
raise OSError(rposix.get_errno(), "os_mkfifo failed")
- return extdef([traits.str, int], s_None, llimpl=mkfifo_llimpl,
+ return extdef([traits.str0, int], s_None, llimpl=mkfifo_llimpl,
export_name=traits.ll_os_name('mkfifo'))
@registering_str_unicode(getattr(os, 'mknod', None))
@@ -1503,7 +1512,7 @@
if res < 0:
raise OSError(rposix.get_errno(), "os_mknod failed")
- return extdef([traits.str, int, int], s_None, llimpl=mknod_llimpl,
+ return extdef([traits.str0, int, int], s_None, llimpl=mknod_llimpl,
export_name=traits.ll_os_name('mknod'))
@registering(os.umask)
@@ -1555,7 +1564,7 @@
if res < 0:
raise OSError(rposix.get_errno(), "os_link failed")
- return extdef([str, str], s_None, llimpl=link_llimpl,
+ return extdef([str0, str0], s_None, llimpl=link_llimpl,
export_name="ll_os.ll_os_link")
@registering_if(os, 'symlink')
@@ -1568,7 +1577,7 @@
if res < 0:
raise OSError(rposix.get_errno(), "os_symlink failed")
- return extdef([str, str], s_None, llimpl=symlink_llimpl,
+ return extdef([str0, str0], s_None, llimpl=symlink_llimpl,
export_name="ll_os.ll_os_symlink")
@registering_if(os, 'fork')
diff --git a/pypy/rpython/module/ll_os_environ.py b/pypy/rpython/module/ll_os_environ.py
--- a/pypy/rpython/module/ll_os_environ.py
+++ b/pypy/rpython/module/ll_os_environ.py
@@ -3,8 +3,11 @@
from pypy.rpython.controllerentry import Controller
from pypy.rpython.extfunc import register_external
from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.module import ll_os
from pypy.rlib import rposix
+str0 = ll_os.str0
+
# ____________________________________________________________
#
# Annotation support to control access to 'os.environ' in the RPython program
@@ -64,7 +67,7 @@
rffi.free_charp(l_name)
return result
-register_external(r_getenv, [str], annmodel.SomeString(can_be_None=True),
+register_external(r_getenv, [str0], annmodel.SomeString(can_be_None=True),
export_name='ll_os.ll_os_getenv',
llimpl=getenv_llimpl)
@@ -93,7 +96,7 @@
if l_oldstring:
rffi.free_charp(l_oldstring)
-register_external(r_putenv, [str, str], annmodel.s_None,
+register_external(r_putenv, [str0, str0], annmodel.s_None,
export_name='ll_os.ll_os_putenv',
llimpl=putenv_llimpl)
@@ -128,7 +131,7 @@
del envkeepalive.byname[name]
rffi.free_charp(l_oldstring)
- register_external(r_unsetenv, [str], annmodel.s_None,
+ register_external(r_unsetenv, [str0], annmodel.s_None,
export_name='ll_os.ll_os_unsetenv',
llimpl=unsetenv_llimpl)
@@ -172,7 +175,7 @@
i += 1
return result
-register_external(r_envkeys, [], [str], # returns a list of strings
+register_external(r_envkeys, [], [str0], # returns a list of strings
export_name='ll_os.ll_os_envkeys',
llimpl=envkeys_llimpl)
@@ -193,6 +196,6 @@
i += 1
return result
-register_external(r_envitems, [], [(str, str)],
+register_external(r_envitems, [], [(str0, str0)],
export_name='ll_os.ll_os_envitems',
llimpl=envitems_llimpl)
diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py
--- a/pypy/rpython/module/ll_os_stat.py
+++ b/pypy/rpython/module/ll_os_stat.py
@@ -236,7 +236,7 @@
def register_stat_variant(name, traits):
if name != 'fstat':
arg_is_path = True
- s_arg = traits.str
+ s_arg = traits.str0
ARG1 = traits.CCHARP
else:
arg_is_path = False
@@ -251,8 +251,6 @@
[s_arg], s_StatResult, traits.ll_os_name(name),
llimpl=posix_stat_llimpl)
- assert traits.str is str
-
if sys.platform.startswith('linux'):
# because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler
_functions = {'stat': 'stat64',
@@ -283,7 +281,7 @@
@func_renamer('os_%s_fake' % (name,))
def posix_fakeimpl(arg):
- if s_arg == str:
+ if s_arg == traits.str0:
arg = hlstr(arg)
st = getattr(os, name)(arg)
fields = [TYPE for fieldname, TYPE in STAT_FIELDS]
diff --git a/pypy/rpython/ootypesystem/test/test_ooann.py b/pypy/rpython/ootypesystem/test/test_ooann.py
--- a/pypy/rpython/ootypesystem/test/test_ooann.py
+++ b/pypy/rpython/ootypesystem/test/test_ooann.py
@@ -231,7 +231,7 @@
a = RPythonAnnotator()
s = a.build_types(oof, [bool])
- assert s == annmodel.SomeString(can_be_None=True)
+ assert annmodel.SomeString(can_be_None=True).contains(s)
def test_oostring():
def oof():
diff --git a/pypy/rpython/test/test_extfunc.py b/pypy/rpython/test/test_extfunc.py
--- a/pypy/rpython/test/test_extfunc.py
+++ b/pypy/rpython/test/test_extfunc.py
@@ -167,3 +167,43 @@
a = RPythonAnnotator(policy=policy)
s = a.build_types(f, [])
assert isinstance(s, annmodel.SomeString)
+
+ def test_str0(self):
+ str0 = annmodel.SomeString(no_nul=True)
+ def os_open(s):
+ pass
+ register_external(os_open, [str0], None)
+ def f(s):
+ return os_open(s)
+ policy = AnnotatorPolicy()
+ policy.allow_someobjects = False
+ a = RPythonAnnotator(policy=policy)
+ a.build_types(f, [str]) # Does not raise
+ assert a.translator.config.translation.check_str_without_nul == False
+ # Now enable the str0 check, and try again with a similar function
+ a.translator.config.translation.check_str_without_nul=True
+ def g(s):
+ return os_open(s)
+ raises(Exception, a.build_types, g, [str])
+ a.build_types(g, [str0]) # Does not raise
+
+ def test_list_of_str0(self):
+ str0 = annmodel.SomeString(no_nul=True)
+ def os_execve(l):
+ pass
+ register_external(os_execve, [[str0]], None)
+ def f(l):
+ return os_execve(l)
+ policy = AnnotatorPolicy()
+ policy.allow_someobjects = False
+ a = RPythonAnnotator(policy=policy)
+ a.build_types(f, [[str]]) # Does not raise
+ assert a.translator.config.translation.check_str_without_nul == False
+ # Now enable the str0 check, and try again with a similar function
+ a.translator.config.translation.check_str_without_nul=True
+ def g(l):
+ return os_execve(l)
+ raises(Exception, a.build_types, g, [[str]])
+ a.build_types(g, [[str0]]) # Does not raise
+
+
diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py
--- a/pypy/translator/c/gc.py
+++ b/pypy/translator/c/gc.py
@@ -11,7 +11,6 @@
from pypy.translator.tool.cbuild import ExternalCompilationInfo
class BasicGcPolicy(object):
- stores_hash_at_the_end = False
def __init__(self, db, thread_enabled=False):
self.db = db
@@ -47,8 +46,7 @@
return ExternalCompilationInfo(
pre_include_bits=['/* using %s */' % (gct.__class__.__name__,),
'#define MALLOC_ZERO_FILLED %d' % (gct.malloc_zero_filled,),
- ],
- post_include_bits=['typedef void *GC_hidden_pointer;']
+ ]
)
def get_prebuilt_hash(self, obj):
@@ -308,7 +306,6 @@
class FrameworkGcPolicy(BasicGcPolicy):
transformerclass = framework.FrameworkGCTransformer
- stores_hash_at_the_end = True
def struct_setup(self, structdefnode, rtti):
if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
diff --git a/pypy/translator/c/test/test_extfunc.py b/pypy/translator/c/test/test_extfunc.py
--- a/pypy/translator/c/test/test_extfunc.py
+++ b/pypy/translator/c/test/test_extfunc.py
@@ -3,6 +3,7 @@
import os, time, sys
from pypy.tool.udir import udir
from pypy.rlib.rarithmetic import r_longlong
+from pypy.annotation import model as annmodel
from pypy.translator.c.test.test_genc import compile
from pypy.translator.c.test.test_standalone import StandaloneTests
posix = __import__(os.name)
@@ -145,7 +146,7 @@
filename = str(py.path.local(__file__))
def call_access(path, mode):
return os.access(path, mode)
- f = compile(call_access, [str, int])
+ f = compile(call_access, [annmodel.s_Str0, int])
for mode in os.R_OK, os.W_OK, os.X_OK, (os.R_OK | os.W_OK | os.X_OK):
assert f(filename, mode) == os.access(filename, mode)
@@ -225,7 +226,7 @@
def test_system():
def does_stuff(cmd):
return os.system(cmd)
- f1 = compile(does_stuff, [str])
+ f1 = compile(does_stuff, [annmodel.s_Str0])
res = f1("echo hello")
assert res == 0
@@ -311,7 +312,7 @@
def test_chdir():
def does_stuff(path):
os.chdir(path)
- f1 = compile(does_stuff, [str])
+ f1 = compile(does_stuff, [annmodel.s_Str0])
curdir = os.getcwd()
try:
os.chdir('..')
@@ -325,7 +326,7 @@
os.rmdir(path)
else:
os.mkdir(path, 0777)
- f1 = compile(does_stuff, [str, bool])
+ f1 = compile(does_stuff, [annmodel.s_Str0, bool])
dirname = str(udir.join('test_mkdir_rmdir'))
f1(dirname, False)
assert os.path.exists(dirname) and os.path.isdir(dirname)
@@ -628,7 +629,7 @@
return os.environ[s]
except KeyError:
return '--missing--'
- func = compile(fn, [str])
+ func = compile(fn, [annmodel.s_Str0])
os.environ.setdefault('USER', 'UNNAMED_USER')
result = func('USER')
assert result == os.environ['USER']
@@ -640,7 +641,7 @@
res = os.environ.get(s)
if res is None: res = '--missing--'
return res
- func = compile(fn, [str])
+ func = compile(fn, [annmodel.s_Str0])
os.environ.setdefault('USER', 'UNNAMED_USER')
result = func('USER')
assert result == os.environ['USER']
@@ -654,7 +655,7 @@
os.environ[s] = t3
os.environ[s] = t4
os.environ[s] = t5
- func = compile(fn, [str, str, str, str, str, str])
+ func = compile(fn, [annmodel.s_Str0] * 6)
func('PYPY_TEST_DICTLIKE_ENVIRON', 'a', 'b', 'c', 'FOOBAR', '42',
expected_extra_mallocs = (2, 3, 4)) # at least two, less than 5
assert _real_getenv('PYPY_TEST_DICTLIKE_ENVIRON') == '42'
@@ -678,7 +679,7 @@
else:
raise Exception("should have raised!")
# os.environ[s5] stays
- func = compile(fn, [str, str, str, str, str])
+ func = compile(fn, [annmodel.s_Str0] * 5)
if hasattr(__import__(os.name), 'unsetenv'):
expected_extra_mallocs = range(2, 10)
# at least 2, less than 10: memory for s1, s2, s3, s4 should be freed
@@ -743,7 +744,7 @@
raise AssertionError("should have failed!")
result = os.listdir(s)
return '/'.join(result)
- func = compile(mylistdir, [str])
+ func = compile(mylistdir, [annmodel.s_Str0])
for testdir in [str(udir), os.curdir]:
result = func(testdir)
result = result.split('/')
diff --git a/pypy/translator/cli/test/runtest.py b/pypy/translator/cli/test/runtest.py
--- a/pypy/translator/cli/test/runtest.py
+++ b/pypy/translator/cli/test/runtest.py
@@ -276,7 +276,7 @@
def get_annotation(x):
if isinstance(x, basestring) and len(x) > 1:
- return SomeString()
+ return SomeString(no_nul='\x00' not in x)
else:
return lltype_to_annotation(typeOf(x))
diff --git a/pypy/translator/driver.py b/pypy/translator/driver.py
--- a/pypy/translator/driver.py
+++ b/pypy/translator/driver.py
@@ -184,6 +184,7 @@
self.standalone = standalone
if standalone:
+ # the 'argv' parameter
inputtypes = [s_list_of_strings]
self.inputtypes = inputtypes
diff --git a/pypy/translator/goal/nanos.py b/pypy/translator/goal/nanos.py
--- a/pypy/translator/goal/nanos.py
+++ b/pypy/translator/goal/nanos.py
@@ -266,7 +266,7 @@
raise NotImplementedError("os.name == %r" % (os.name,))
def getenv(space, w_name):
- name = space.str_w(w_name)
+ name = space.str0_w(w_name)
return space.wrap(os.environ.get(name))
getenv_w = interp2app(getenv)
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -159,6 +159,8 @@
## if config.translation.type_system == 'ootype':
## config.objspace.usemodules.suggest(rbench=True)
+ config.translation.suggest(check_str_without_nul=True)
+
if config.translation.thread:
config.objspace.usemodules.thread = True
elif config.objspace.usemodules.thread:
More information about the pypy-commit
mailing list