[pypy-commit] pypy jit-short_from_state: hg merge c3cdcacec880
hakanardo
noreply at buildbot.pypy.org
Mon Jul 25 23:21:39 CEST 2011
Author: Hakan Ardo <hakan at debian.org>
Branch: jit-short_from_state
Changeset: r45987:26de1fba7350
Date: 2011-07-25 19:36 +0200
http://bitbucket.org/pypy/pypy/changeset/26de1fba7350/
Log: hg merge c3cdcacec880
diff too long, truncating to 10000 out of 15314 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,6 +1,7 @@
syntax: glob
*.py[co]
*~
+.*.swp
syntax: regexp
^testresult$
@@ -38,6 +39,8 @@
^pypy/translator/benchmark/shootout_benchmarks$
^pypy/translator/goal/pypy-translation-snapshot$
^pypy/translator/goal/pypy-c
+^pypy/translator/goal/pypy-jvm
+^pypy/translator/goal/pypy-jvm.jar
^pypy/translator/goal/.+\.exe$
^pypy/translator/goal/.+\.dll$
^pypy/translator/goal/target.+-c$
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -185,6 +185,7 @@
Jim Baker
Philip Jenvey
Rodrigo Araújo
+ Brett Cannon
Heinrich-Heine University, Germany
Open End AB (formerly AB Strakt), Sweden
diff --git a/lib-python/modified-2.7/distutils/cygwinccompiler.py b/lib-python/modified-2.7/distutils/cygwinccompiler.py
--- a/lib-python/modified-2.7/distutils/cygwinccompiler.py
+++ b/lib-python/modified-2.7/distutils/cygwinccompiler.py
@@ -75,6 +75,9 @@
elif msc_ver == '1500':
# VS2008 / MSVC 9.0
return ['msvcr90']
+ elif msc_ver == '1600':
+ # VS2010 / MSVC 10.0
+ return ['msvcr100']
else:
raise ValueError("Unknown MS Compiler version %s " % msc_ver)
diff --git a/lib-python/modified-2.7/distutils/sysconfig_pypy.py b/lib-python/modified-2.7/distutils/sysconfig_pypy.py
--- a/lib-python/modified-2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/modified-2.7/distutils/sysconfig_pypy.py
@@ -116,6 +116,12 @@
if compiler.compiler_type == "unix":
compiler.compiler_so.extend(['-fPIC', '-Wimplicit'])
compiler.shared_lib_extension = get_config_var('SO')
+ if "CFLAGS" in os.environ:
+ cflags = os.environ["CFLAGS"]
+ compiler.compiler.append(cflags)
+ compiler.compiler_so.append(cflags)
+ compiler.linker_so.append(cflags)
+
from sysconfig_cpython import (
parse_makefile, _variable_rx, expand_makefile_vars)
diff --git a/lib-python/modified-2.7/pickle.py b/lib-python/modified-2.7/pickle.py
--- a/lib-python/modified-2.7/pickle.py
+++ b/lib-python/modified-2.7/pickle.py
@@ -168,7 +168,7 @@
# Pickling machinery
-class Pickler:
+class Pickler(object):
def __init__(self, file, protocol=None):
"""This takes a file-like object for writing a pickle data stream.
diff --git a/lib-python/2.7/test/test_sets.py b/lib-python/modified-2.7/test/test_sets.py
copy from lib-python/2.7/test/test_sets.py
copy to lib-python/modified-2.7/test/test_sets.py
--- a/lib-python/2.7/test/test_sets.py
+++ b/lib-python/modified-2.7/test/test_sets.py
@@ -686,7 +686,9 @@
set_list = sorted(self.set)
self.assertEqual(len(dup_list), len(set_list))
for i, el in enumerate(dup_list):
- self.assertIs(el, set_list[i])
+ # Object identity is not guarnteed for immutable objects, so we
+ # can't use assertIs here.
+ self.assertEqual(el, set_list[i])
def test_deep_copy(self):
dup = copy.deepcopy(self.set)
diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/modified-2.7/test/test_tarfile.py
copy from lib-python/2.7/test/test_tarfile.py
copy to lib-python/modified-2.7/test/test_tarfile.py
--- a/lib-python/2.7/test/test_tarfile.py
+++ b/lib-python/modified-2.7/test/test_tarfile.py
@@ -169,6 +169,7 @@
except tarfile.ReadError:
self.fail("tarfile.open() failed on empty archive")
self.assertListEqual(tar.getmembers(), [])
+ tar.close()
def test_null_tarfile(self):
# Test for issue6123: Allow opening empty archives.
@@ -207,16 +208,21 @@
fobj = open(self.tarname, "rb")
tar = tarfile.open(fileobj=fobj, mode=self.mode)
self.assertEqual(tar.name, os.path.abspath(fobj.name))
+ tar.close()
def test_no_name_attribute(self):
- data = open(self.tarname, "rb").read()
+ f = open(self.tarname, "rb")
+ data = f.read()
+ f.close()
fobj = StringIO.StringIO(data)
self.assertRaises(AttributeError, getattr, fobj, "name")
tar = tarfile.open(fileobj=fobj, mode=self.mode)
self.assertEqual(tar.name, None)
def test_empty_name_attribute(self):
- data = open(self.tarname, "rb").read()
+ f = open(self.tarname, "rb")
+ data = f.read()
+ f.close()
fobj = StringIO.StringIO(data)
fobj.name = ""
tar = tarfile.open(fileobj=fobj, mode=self.mode)
@@ -515,6 +521,7 @@
self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1")
tarinfo = self.tar.getmember("pax/umlauts-�������")
self._test_member(tarinfo, size=7011, chksum=md5_regtype)
+ self.tar.close()
class LongnameTest(ReadTest):
@@ -675,6 +682,7 @@
tar = tarfile.open(tmpname, self.mode)
tarinfo = tar.gettarinfo(path)
self.assertEqual(tarinfo.size, 0)
+ tar.close()
finally:
os.rmdir(path)
@@ -692,6 +700,7 @@
tar.gettarinfo(target)
tarinfo = tar.gettarinfo(link)
self.assertEqual(tarinfo.size, 0)
+ tar.close()
finally:
os.remove(target)
os.remove(link)
@@ -704,6 +713,7 @@
tar = tarfile.open(tmpname, self.mode)
tarinfo = tar.gettarinfo(path)
self.assertEqual(tarinfo.size, 0)
+ tar.close()
finally:
os.remove(path)
@@ -722,6 +732,7 @@
tar.add(dstname)
os.chdir(cwd)
self.assertTrue(tar.getnames() == [], "added the archive to itself")
+ tar.close()
def test_exclude(self):
tempdir = os.path.join(TEMPDIR, "exclude")
@@ -742,6 +753,7 @@
tar = tarfile.open(tmpname, "r")
self.assertEqual(len(tar.getmembers()), 1)
self.assertEqual(tar.getnames()[0], "empty_dir")
+ tar.close()
finally:
shutil.rmtree(tempdir)
@@ -859,7 +871,9 @@
fobj.close()
elif self.mode.endswith("bz2"):
dec = bz2.BZ2Decompressor()
- data = open(tmpname, "rb").read()
+ f = open(tmpname, "rb")
+ data = f.read()
+ f.close()
data = dec.decompress(data)
self.assertTrue(len(dec.unused_data) == 0,
"found trailing data")
@@ -938,6 +952,7 @@
"unable to read longname member")
self.assertEqual(tarinfo.linkname, member.linkname,
"unable to read longname member")
+ tar.close()
def test_longname_1023(self):
self._test(("longnam/" * 127) + "longnam")
@@ -1030,6 +1045,7 @@
else:
n = tar.getmembers()[0].name
self.assertTrue(name == n, "PAX longname creation failed")
+ tar.close()
def test_pax_global_header(self):
pax_headers = {
@@ -1058,6 +1074,7 @@
tarfile.PAX_NUMBER_FIELDS[key](val)
except (TypeError, ValueError):
self.fail("unable to convert pax header field")
+ tar.close()
def test_pax_extended_header(self):
# The fields from the pax header have priority over the
@@ -1077,6 +1094,7 @@
self.assertEqual(t.pax_headers, pax_headers)
self.assertEqual(t.name, "foo")
self.assertEqual(t.uid, 123)
+ tar.close()
class UstarUnicodeTest(unittest.TestCase):
@@ -1120,6 +1138,7 @@
tarinfo.name = "foo"
tarinfo.uname = u"���"
self.assertRaises(UnicodeError, tar.addfile, tarinfo)
+ tar.close()
def test_unicode_argument(self):
tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict")
@@ -1174,6 +1193,7 @@
tar = tarfile.open(tmpname, format=self.format, encoding="ascii",
errors=handler)
self.assertEqual(tar.getnames()[0], name)
+ tar.close()
self.assertRaises(UnicodeError, tarfile.open, tmpname,
encoding="ascii", errors="strict")
@@ -1186,6 +1206,7 @@
tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1",
errors="utf-8")
self.assertEqual(tar.getnames()[0], "���/" + u"�".encode("utf8"))
+ tar.close()
class AppendTest(unittest.TestCase):
@@ -1213,6 +1234,7 @@
def _test(self, names=["bar"], fileobj=None):
tar = tarfile.open(self.tarname, fileobj=fileobj)
self.assertEqual(tar.getnames(), names)
+ tar.close()
def test_non_existing(self):
self._add_testfile()
@@ -1231,7 +1253,9 @@
def test_fileobj(self):
self._create_testtar()
- data = open(self.tarname).read()
+ f = open(self.tarname)
+ data = f.read()
+ f.close()
fobj = StringIO.StringIO(data)
self._add_testfile(fobj)
fobj.seek(0)
@@ -1257,7 +1281,9 @@
# Append mode is supposed to fail if the tarfile to append to
# does not end with a zero block.
def _test_error(self, data):
- open(self.tarname, "wb").write(data)
+ f = open(self.tarname, "wb")
+ f.write(data)
+ f.close()
self.assertRaises(tarfile.ReadError, self._add_testfile)
def test_null(self):
diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py
--- a/lib_pypy/_ctypes/__init__.py
+++ b/lib_pypy/_ctypes/__init__.py
@@ -18,7 +18,16 @@
if _os.name in ("nt", "ce"):
from _rawffi import FormatError
from _rawffi import check_HRESULT as _check_HRESULT
- CopyComPointer = None # XXX
+
+ def CopyComPointer(src, dst):
+ from ctypes import c_void_p, cast
+ if src:
+ hr = src[0][0].AddRef(src)
+ if hr & 0x80000000:
+ return hr
+ dst[0] = cast(src, c_void_p).value
+ return 0
+
LoadLibrary = dlopen
from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -48,7 +48,8 @@
return self.from_param(as_parameter)
def get_ffi_param(self, value):
- return self.from_param(value)._to_ffi_param()
+ cdata = self.from_param(value)
+ return cdata, cdata._to_ffi_param()
def get_ffi_argtype(self):
if self._ffiargtype:
@@ -139,7 +140,10 @@
return buffer(self._buffer)
def _get_b_base(self):
- return self._base
+ try:
+ return self._base
+ except AttributeError:
+ return None
_b_base_ = property(_get_b_base)
_b_needsfree_ = False
@@ -218,5 +222,7 @@
'z' : _ffi.types.void_p,
'O' : _ffi.types.void_p,
'Z' : _ffi.types.void_p,
+ 'X' : _ffi.types.void_p,
+ 'v' : _ffi.types.sshort,
}
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -322,20 +322,20 @@
RuntimeWarning, stacklevel=2)
if self._com_index:
- assert False, 'TODO2'
from ctypes import cast, c_void_p, POINTER
if not args:
raise ValueError(
"native COM method call without 'this' parameter"
)
- thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents
- argtypes = [c_void_p] + list(argtypes)
- args = list(args)
- args[0] = args[0].value
+ thisarg = cast(args[0], POINTER(POINTER(c_void_p)))
+ keepalives, newargs, argtypes, outargs = self._convert_args(argtypes,
+ args[1:], kwargs)
+ newargs.insert(0, args[0].value)
+ argtypes.insert(0, c_void_p)
else:
thisarg = None
-
- newargs, argtypes, outargs = self._convert_args(argtypes, args, kwargs)
+ keepalives, newargs, argtypes, outargs = self._convert_args(argtypes,
+ args, kwargs)
funcptr = self._getfuncptr(argtypes, self._restype_, thisarg)
result = self._call_funcptr(funcptr, *newargs)
@@ -343,6 +343,11 @@
if not outargs:
return result
+
+ simple_cdata = type(c_void_p()).__bases__[0]
+ outargs = [x.value if type(x).__bases__[0] is simple_cdata else x
+ for x in outargs]
+
if len(outargs) == 1:
return outargs[0]
return tuple(outargs)
@@ -398,10 +403,10 @@
# extract the address from the object's virtual table
if not thisarg:
raise ValueError("COM method call without VTable")
- ptr = thisarg[self._com_index - 0x1000]
- argshapes = [arg._ffiargshape for arg in argtypes]
- resshape = restype._ffiargshape
- return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_)
+ ptr = thisarg[0][self._com_index - 0x1000]
+ ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
+ ffires = restype.get_ffi_argtype()
+ return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires)
cdll = self.dll._handle
try:
@@ -434,16 +439,15 @@
@classmethod
def _conv_param(cls, argtype, arg):
if isinstance(argtype, _CDataMeta):
- #arg = argtype.from_param(arg)
- arg = argtype.get_ffi_param(arg)
- return arg, argtype
+ cobj, ffiparam = argtype.get_ffi_param(arg)
+ return cobj, ffiparam, argtype
if argtype is not None:
arg = argtype.from_param(arg)
if hasattr(arg, '_as_parameter_'):
arg = arg._as_parameter_
if isinstance(arg, _CData):
- return arg._to_ffi_param(), type(arg)
+ return arg, arg._to_ffi_param(), type(arg)
#
# non-usual case: we do the import here to save a lot of code in the
# jit trace of the normal case
@@ -460,19 +464,16 @@
else:
raise TypeError("Don't know how to handle %s" % (arg,))
- return cobj._to_ffi_param(), type(cobj)
+ return cobj, cobj._to_ffi_param(), type(cobj)
def _convert_args(self, argtypes, args, kwargs, marker=object()):
newargs = []
outargs = []
+ keepalives = []
newargtypes = []
total = len(args)
paramflags = self._paramflags
-
- if self._com_index:
- inargs_idx = 1
- else:
- inargs_idx = 0
+ inargs_idx = 0
if not paramflags and total < len(argtypes):
raise TypeError("not enough arguments")
@@ -496,7 +497,8 @@
val = defval
if val is marker:
val = 0
- newarg, newargtype = self._conv_param(argtype, val)
+ keepalive, newarg, newargtype = self._conv_param(argtype, val)
+ keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
elif flag in (0, PARAMFLAG_FIN):
@@ -512,28 +514,32 @@
raise TypeError("required argument '%s' missing" % name)
else:
raise TypeError("not enough arguments")
- newarg, newargtype = self._conv_param(argtype, val)
+ keepalive, newarg, newargtype = self._conv_param(argtype, val)
+ keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
elif flag == PARAMFLAG_FOUT:
if defval is not marker:
outargs.append(defval)
- newarg, newargtype = self._conv_param(argtype, defval)
+ keepalive, newarg, newargtype = self._conv_param(argtype, defval)
else:
import ctypes
val = argtype._type_()
outargs.append(val)
+ keepalive = None
newarg = ctypes.byref(val)
newargtype = type(newarg)
+ keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
else:
raise ValueError("paramflag %d not yet implemented" % flag)
else:
try:
- newarg, newargtype = self._conv_param(argtype, args[i])
+ keepalive, newarg, newargtype = self._conv_param(argtype, args[i])
except (UnicodeError, TypeError, ValueError), e:
raise ArgumentError(str(e))
+ keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
inargs_idx += 1
@@ -542,12 +548,13 @@
extra = args[len(newargs):]
for i, arg in enumerate(extra):
try:
- newarg, newargtype = self._conv_param(None, arg)
+ keepalive, newarg, newargtype = self._conv_param(None, arg)
except (UnicodeError, TypeError, ValueError), e:
raise ArgumentError(str(e))
+ keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
- return newargs, newargtypes, outargs
+ return keepalives, newargs, newargtypes, outargs
def _wrap_result(self, restype, result):
@@ -587,13 +594,7 @@
retval = None
- if self._com_index:
- if resbuffer[0] & 0x80000000:
- raise get_com_error(resbuffer[0],
- self._com_iid, argsandobjs[0])
- else:
- retval = int(resbuffer[0])
- elif restype is not None:
+ if restype is not None:
checker = getattr(self.restype, '_check_retval_', None)
if checker:
val = restype(result)
@@ -601,7 +602,13 @@
# classes defining a new type, and their subclasses
if '_type_' in restype.__dict__:
val = val.value
- retval = checker(val)
+ # XXX Raise a COMError when restype is HRESULT and
+ # checker(val) fails. How to check for restype == HRESULT?
+ if self._com_index:
+ if result & 0x80000000:
+ raise get_com_error(result, None, None)
+ else:
+ retval = checker(val)
elif not isinstance(restype, _CDataMeta):
retval = restype(result)
else:
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -216,10 +216,15 @@
result.value = property(_getvalue, _setvalue)
elif tp == 'X':
- from ctypes import windll
- SysAllocStringLen = windll.oleaut32.SysAllocStringLen
- SysStringLen = windll.oleaut32.SysStringLen
- SysFreeString = windll.oleaut32.SysFreeString
+ from ctypes import WinDLL
+ # Use WinDLL("oleaut32") instead of windll.oleaut32
+ # because the latter is a shared (cached) object; and
+ # other code may set their own restypes. We need out own
+ # restype here.
+ oleaut32 = WinDLL("oleaut32")
+ SysAllocStringLen = oleaut32.SysAllocStringLen
+ SysStringLen = oleaut32.SysStringLen
+ SysFreeString = oleaut32.SysFreeString
def _getvalue(self):
addr = self._buffer[0]
if addr == 0:
diff --git a/lib_pypy/binascii.py b/lib_pypy/binascii.py
--- a/lib_pypy/binascii.py
+++ b/lib_pypy/binascii.py
@@ -659,7 +659,7 @@
crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8)
#/* Note: (crc >> 8) MUST zero fill on left
- result = crc ^ 0xffffffffL
+ result = crc ^ 0xffffffffL
if result > 2**31:
result = ((result + 2**31) % 2**32) - 2**31
diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py
--- a/lib_pypy/cPickle.py
+++ b/lib_pypy/cPickle.py
@@ -27,9 +27,9 @@
PythonPickler.__init__(self, self.__f, args[0], **kw)
else:
PythonPickler.__init__(self, *args, **kw)
-
+
def memoize(self, obj):
- self.memo[None] = None # cPickle starts counting at one
+ self.memo[id(None)] = None # cPickle starts counting at one
return PythonPickler.memoize(self, obj)
def getvalue(self):
diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py
--- a/lib_pypy/pyrepl/unix_console.py
+++ b/lib_pypy/pyrepl/unix_console.py
@@ -384,15 +384,19 @@
self.__maybe_write_code(self._smkx)
- self.old_sigwinch = signal.signal(
- signal.SIGWINCH, self.__sigwinch)
+ try:
+ self.old_sigwinch = signal.signal(
+ signal.SIGWINCH, self.__sigwinch)
+ except ValueError:
+ pass
def restore(self):
self.__maybe_write_code(self._rmkx)
self.flushoutput()
tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate)
- signal.signal(signal.SIGWINCH, self.old_sigwinch)
+ if hasattr(self, 'old_sigwinch'):
+ signal.signal(signal.SIGWINCH, self.old_sigwinch)
def __sigwinch(self, signum, frame):
self.height, self.width = self.getheightwidth()
diff --git a/pypy/config/config.py b/pypy/config/config.py
--- a/pypy/config/config.py
+++ b/pypy/config/config.py
@@ -81,6 +81,12 @@
(self.__class__, name))
return self._cfgimpl_values[name]
+ def __dir__(self):
+ from_type = dir(type(self))
+ from_dict = list(self.__dict__)
+ extras = list(self._cfgimpl_values)
+ return sorted(set(extras + from_type + from_dict))
+
def __delattr__(self, name):
# XXX if you use delattr you are responsible for all bad things
# happening
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -327,6 +327,9 @@
BoolOption("mutable_builtintypes",
"Allow the changing of builtin types", default=False,
requires=[("objspace.std.builtinshortcut", True)]),
+ BoolOption("withidentitydict",
+ "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not",
+ default=True),
]),
])
diff --git a/pypy/config/support.py b/pypy/config/support.py
--- a/pypy/config/support.py
+++ b/pypy/config/support.py
@@ -9,7 +9,7 @@
return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option
if sys.platform == 'darwin':
return darwin_get_cpu_count()
- elif sys.platform != 'linux2':
+ elif not sys.platform.startswith('linux'):
return 1 # implement me
try:
if isinstance(filename_or_file, str):
diff --git a/pypy/config/test/test_config.py b/pypy/config/test/test_config.py
--- a/pypy/config/test/test_config.py
+++ b/pypy/config/test/test_config.py
@@ -63,6 +63,20 @@
py.test.raises(ConfigError, 'config.gc.name = "ref"')
config.gc.name = "framework"
+def test___dir__():
+ descr = make_description()
+ config = Config(descr, bool=False)
+ attrs = dir(config)
+ assert '__repr__' in attrs # from the type
+ assert '_cfgimpl_values' in attrs # from self
+ assert 'gc' in attrs # custom attribute
+ assert 'objspace' in attrs # custom attribute
+ #
+ attrs = dir(config.gc)
+ assert 'name' in attrs
+ assert 'dummy' in attrs
+ assert 'float' in attrs
+
def test_arbitrary_option():
descr = OptionDescription("top", "", [
ArbitraryOption("a", "no help", default=None)
diff --git a/pypy/config/test/test_support.py b/pypy/config/test/test_support.py
--- a/pypy/config/test/test_support.py
+++ b/pypy/config/test/test_support.py
@@ -40,7 +40,7 @@
return self._value
def test_cpuinfo_linux():
- if sys.platform != 'linux2':
+ if not sys.platform.startswith('linux'):
py.test.skip("linux only")
saved = os.environ
try:
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -140,7 +140,10 @@
["annotate", "rtype", "backendopt", "database", "source",
"pyjitpl"],
default=None, cmdline="--fork-before"),
-
+ BoolOption("dont_write_c_files",
+ "Make the C backend write everyting to /dev/null. " +
+ "Useful for benchmarking, so you don't actually involve the disk",
+ default=False, cmdline="--dont-write-c-files"),
ArbitraryOption("instrumentctl", "internal",
default=None),
StrOption("output", "Output file name", cmdline="--output"),
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -929,6 +929,19 @@
located in the ``py/bin/`` directory. For switches to
modify test execution pass the ``-h`` option.
+Coverage reports
+----------------
+
+In order to get coverage reports the `pytest-cov`_ plugin is included.
+it adds some extra requirements ( coverage_ and `cov-core`_ )
+and can once they are installed coverage testing can be invoked via::
+
+ python test_all.py --cov file_or_direcory_to_cover file_or_directory
+
+.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov
+.. _`coverage`: http://pypi.python.org/pypi/coverage
+.. _`cov-core`: http://pypi.python.org/pypi/cov-core
+
Test conventions
----------------
diff --git a/pypy/doc/config/objspace.std.withidentitydict.txt b/pypy/doc/config/objspace.std.withidentitydict.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.std.withidentitydict.txt
@@ -0,0 +1,21 @@
+=============================
+objspace.std.withidentitydict
+=============================
+
+* **name:** withidentitydict
+
+* **description:** enable a dictionary strategy for "by identity" comparisons
+
+* **command-line:** --objspace-std-withidentitydict
+
+* **command-line for negation:** --no-objspace-std-withidentitydict
+
+* **option type:** boolean option
+
+* **default:** True
+
+
+Enable a dictionary strategy specialized for instances of classes which
+compares "by identity", which is the default unless you override ``__hash__``,
+``__eq__`` or ``__cmp__``. This strategy will be used only with new-style
+classes.
diff --git a/pypy/doc/config/translation.dont_write_c_files.txt b/pypy/doc/config/translation.dont_write_c_files.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/translation.dont_write_c_files.txt
@@ -0,0 +1,4 @@
+write the generated C files to ``/dev/null`` instead of to the disk. Useful if
+you want to use translate.py as a benchmark and don't want to access the disk.
+
+.. _`translation documentation`: ../translation.html
diff --git a/pypy/doc/config/translation.gc.txt b/pypy/doc/config/translation.gc.txt
--- a/pypy/doc/config/translation.gc.txt
+++ b/pypy/doc/config/translation.gc.txt
@@ -1,4 +1,6 @@
-Choose the Garbage Collector used by the translated program:
+Choose the Garbage Collector used by the translated program.
+The good performing collectors are "hybrid" and "minimark".
+The default is "minimark".
- "ref": reference counting. Takes very long to translate and the result is
slow.
@@ -11,3 +13,12 @@
older generation.
- "boehm": use the Boehm conservative GC.
+
+ - "hybrid": a hybrid collector of "generation" together with a
+ mark-n-sweep old space
+
+ - "markcompact": a slow, but memory-efficient collector,
+ influenced e.g. by Smalltalk systems.
+
+ - "minimark": a generational mark-n-sweep collector with good
+ performance. Includes page marking for large arrays.
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -211,6 +211,38 @@
>>>> print d1['a']
42
+Mutating classes of objects which are already used as dictionary keys
+---------------------------------------------------------------------
+
+Consider the following snippet of code::
+
+ class X(object):
+ pass
+
+ def __evil_eq__(self, other):
+ print 'hello world'
+ return False
+
+ def evil(y):
+ d = {x(): 1}
+ X.__eq__ = __evil_eq__
+ d[y] # might trigger a call to __eq__?
+
+In CPython, __evil_eq__ **might** be called, although there is no way to write
+a test which reliably calls it. It happens if ``y is not x`` and ``hash(y) ==
+hash(x)``, where ``hash(x)`` is computed when ``x`` is inserted into the
+dictionary. If **by chance** the condition is satisfied, then ``__evil_eq__``
+is called.
+
+PyPy uses a special strategy to optimize dictionaries whose keys are instances
+of user-defined classes which do not override the default ``__hash__``,
+``__eq__`` and ``__cmp__``: when using this strategy, ``__eq__`` and
+``__cmp__`` are never called, but instead the lookup is done by identity, so
+in the case above it is guaranteed that ``__eq__`` won't be called.
+
+Note that in all other cases (e.g., if you have a custom ``__hash__`` and
+``__eq__`` in ``y``) the behavior is exactly the same as CPython.
+
Ignored exceptions
-----------------------
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -19,12 +19,12 @@
section
* Write them in pure python and use direct libffi low-level bindings, See
- \_rawffi_ module description.
+ \_ffi_ module description.
* Write them in RPython as mixedmodule_, using *rffi* as bindings.
.. _ctypes: #CTypes
-.. _\_rawffi: #LibFFI
+.. _\_ffi: #LibFFI
.. _mixedmodule: #Mixed Modules
CTypes
@@ -42,41 +42,50 @@
platform-dependent details (compiling small snippets of C code and running
them), so it'll benefit not pypy-related ctypes-based modules as well.
+ctypes call are optimized by the JIT and the resulting machine code contains a
+direct call to the target C function. However, due to the very dynamic nature
+of ctypes, some overhead over a bare C call is still present, in particular to
+check/convert the types of the parameters. Moreover, even if most calls are
+optimized, some cannot and thus need to follow the slow path, not optimized by
+the JIT.
+
.. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure
+.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html
Pros
----
-Stable, CPython-compatible API
+Stable, CPython-compatible API. Most calls are fast, optimized by JIT.
Cons
----
-Only pure-python code (slow), problems with platform-dependency (although
-we partially solve those). PyPy implementation is now very slow.
+Problems with platform-dependency (although we partially solve
+those). Although the JIT optimizes ctypes calls, some overhead is still
+present. The slow-path is very slow.
-_`CPython ctypes`: http://python.net/crew/theller/ctypes/
LibFFI
======
Mostly in order to be able to write a ctypes module, we developed a very
-low-level libffi bindings. (libffi is a C-level library for dynamic calling,
+low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling,
which is used by CPython ctypes). This library provides stable and usable API,
although it's API is a very low-level one. It does not contain any
-magic.
+magic. It is also optimized by the JIT, but has much less overhead than ctypes.
Pros
----
-Works. Combines disadvantages of using ctypes with disadvantages of
-using mixed modules. Probably more suitable for a delicate code
-where ctypes magic goes in a way.
+It Works. Probably more suitable for a delicate code where ctypes magic goes
+in a way. All calls are optimized by the JIT, there is no slow path as in
+ctypes.
Cons
----
-Slow. CPython-incompatible API, very rough and low-level
+It combines disadvantages of using ctypes with disadvantages of using mixed
+modules. CPython-incompatible API, very rough and low-level.
Mixed Modules
=============
@@ -87,15 +96,15 @@
* a mixed module needs to be written in RPython, which is far more
complicated than Python (XXX link)
-* due to lack of separate compilation (as of April 2008), each
+* due to lack of separate compilation (as of July 2011), each
compilation-check requires to recompile whole PyPy python interpreter,
which takes 0.5-1h. We plan to solve this at some point in near future.
* although rpython is a garbage-collected language, the border between
C and RPython needs to be managed by hand (each object that goes into the
- C level must be explicitly freed) XXX we try to solve this
+ C level must be explicitly freed).
-Some document is available `here`_
+Some documentation is available `here`_
.. _`here`: rffi.html
diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst
--- a/pypy/doc/getting-started.rst
+++ b/pypy/doc/getting-started.rst
@@ -51,7 +51,7 @@
---------------
PyPy is ready to be executed as soon as you unpack the tarball or the zip
-file, with no need install it in any specific location::
+file, with no need to install it in any specific location::
$ tar xf pypy-1.5-linux.tar.bz2
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -11,6 +11,10 @@
Getting into PyPy ...
=============================================
+* `Getting started`_: how to install and run the PyPy Python interpreter
+
+* `FAQ`_: some frequently asked questions.
+
* `Release 1.5`_: the latest official release
* `PyPy Blog`_: news and status info about PyPy
@@ -26,13 +30,6 @@
Documentation for the PyPy Python Interpreter
===============================================
-`getting started`_ provides hands-on instructions
-including a two-liner to run the PyPy Python interpreter
-on your system, examples on advanced features and
-entry points for using the `RPython toolchain`_.
-
-`FAQ`_ contains some frequently asked questions.
-
New features of PyPy's Python Interpreter and
Translation Framework:
diff --git a/pypy/doc/interpreter-optimizations.rst b/pypy/doc/interpreter-optimizations.rst
--- a/pypy/doc/interpreter-optimizations.rst
+++ b/pypy/doc/interpreter-optimizations.rst
@@ -157,32 +157,6 @@
A more advanced version of sharing dicts, called *map dicts,* is available
with the :config:`objspace.std.withmapdict` option.
-Builtin-Shadowing
-+++++++++++++++++
-
-Usually the calling of builtins in Python requires two dictionary lookups: first
-to see whether the current global dictionary contains an object with the same
-name, then a lookup in the ``__builtin__`` dictionary. This is somehow
-circumvented by storing an often used builtin into a local variable to get
-the fast local lookup (which is a rather strange and ugly hack).
-
-The same problem is solved in a different way by "wary" dictionaries. They are
-another dictionary representation used together with multidicts. This
-representation is used only for module dictionaries. The representation checks on
-every setitem whether the key that is used is the name of a builtin. If this is
-the case, the dictionary is marked as shadowing that particular builtin.
-
-To identify calls to builtins easily, a new bytecode (``CALL_LIKELY_BUILTIN``)
-is introduced. Whenever it is executed, the globals dictionary is checked
-to see whether it masks the builtin (which is possible without a dictionary
-lookup). Then the ``__builtin__`` dict is checked in the same way,
-to see whether somebody replaced the real builtin with something else. In the
-common case, the program didn't do any of these; the proper builtin can then
-be called without using any dictionary lookup at all.
-
-You can enable this feature with the
-:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option.
-
List Optimizations
------------------
@@ -289,34 +263,6 @@
You can enable this feature with the :config:`objspace.opcodes.CALL_METHOD`
option.
-.. _`call likely builtin`:
-
-CALL_LIKELY_BUILTIN
-+++++++++++++++++++
-
-A often heard "tip" for speeding up Python programs is to give an often used
-builtin a local name, since local lookups are faster than lookups of builtins,
-which involve doing two dictionary lookups: one in the globals dictionary and
-one in the the builtins dictionary. PyPy approaches this problem at the
-implementation level, with the introduction of the new ``CALL_LIKELY_BUILTIN``
-bytecode. This bytecode is produced by the compiler for a call whose target is
-the name of a builtin. Since such a syntactic construct is very often actually
-invoking the expected builtin at run-time, this information can be used to make
-the call to the builtin directly, without going through any dictionary lookup.
-
-However, it can occur that the name is shadowed by a global name from the
-current module. To catch this case, a special dictionary implementation for
-multidicts is introduced, which is used for the dictionaries of modules. This
-implementation keeps track which builtin name is shadowed by it. The
-``CALL_LIKELY_BUILTIN`` bytecode asks the dictionary whether it is shadowing the
-builtin that is about to be called and asks the dictionary of ``__builtin__``
-whether the original builtin was changed. These two checks are cheaper than
-full lookups. In the common case, neither of these cases is true, so the
-builtin can be directly invoked.
-
-You can enable this feature with the
-:config:`objspace.opcodes.CALL_LIKELY_BUILTIN` option.
-
.. more here?
Overall Effects
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -32,6 +32,24 @@
modules that relies on third-party libraries. See below how to get
and build them.
+Preping Windows for the Large Build
+-----------------------------------
+
+Normally 32bit programs are limited to 2GB of memory on Windows. It is
+possible to raise this limit, to 3GB on Windows 32bit, and almost 4GB
+on Windows 64bit.
+
+On Windows 32bit, it is necessary to modify the system: follow
+http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=9583842&linkID=9240617
+to enable the "3GB" feature, and reboot. This step is not necessary on
+Windows 64bit.
+
+Then you need to execute::
+
+ editbin /largeaddressaware pypy.exe
+
+on the pypy.exe file you compiled.
+
Installing external packages
----------------------------
diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -2541,8 +2541,9 @@
class ASTVisitor(object):
def visit_sequence(self, seq):
- for node in seq:
- node.walkabout(self)
+ if seq is not None:
+ for node in seq:
+ node.walkabout(self)
def default_visitor(self, node):
raise NodeVisitorNotImplemented
@@ -2673,46 +2674,36 @@
class GenericASTVisitor(ASTVisitor):
def visit_Module(self, node):
- if node.body:
- self.visit_sequence(node.body)
+ self.visit_sequence(node.body)
def visit_Interactive(self, node):
- if node.body:
- self.visit_sequence(node.body)
+ self.visit_sequence(node.body)
def visit_Expression(self, node):
node.body.walkabout(self)
def visit_Suite(self, node):
- if node.body:
- self.visit_sequence(node.body)
+ self.visit_sequence(node.body)
def visit_FunctionDef(self, node):
node.args.walkabout(self)
- if node.body:
- self.visit_sequence(node.body)
- if node.decorator_list:
- self.visit_sequence(node.decorator_list)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.decorator_list)
def visit_ClassDef(self, node):
- if node.bases:
- self.visit_sequence(node.bases)
- if node.body:
- self.visit_sequence(node.body)
- if node.decorator_list:
- self.visit_sequence(node.decorator_list)
+ self.visit_sequence(node.bases)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.decorator_list)
def visit_Return(self, node):
if node.value:
node.value.walkabout(self)
def visit_Delete(self, node):
- if node.targets:
- self.visit_sequence(node.targets)
+ self.visit_sequence(node.targets)
def visit_Assign(self, node):
- if node.targets:
- self.visit_sequence(node.targets)
+ self.visit_sequence(node.targets)
node.value.walkabout(self)
def visit_AugAssign(self, node):
@@ -2722,37 +2713,29 @@
def visit_Print(self, node):
if node.dest:
node.dest.walkabout(self)
- if node.values:
- self.visit_sequence(node.values)
+ self.visit_sequence(node.values)
def visit_For(self, node):
node.target.walkabout(self)
node.iter.walkabout(self)
- if node.body:
- self.visit_sequence(node.body)
- if node.orelse:
- self.visit_sequence(node.orelse)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.orelse)
def visit_While(self, node):
node.test.walkabout(self)
- if node.body:
- self.visit_sequence(node.body)
- if node.orelse:
- self.visit_sequence(node.orelse)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.orelse)
def visit_If(self, node):
node.test.walkabout(self)
- if node.body:
- self.visit_sequence(node.body)
- if node.orelse:
- self.visit_sequence(node.orelse)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.orelse)
def visit_With(self, node):
node.context_expr.walkabout(self)
if node.optional_vars:
node.optional_vars.walkabout(self)
- if node.body:
- self.visit_sequence(node.body)
+ self.visit_sequence(node.body)
def visit_Raise(self, node):
if node.type:
@@ -2763,18 +2746,13 @@
node.tback.walkabout(self)
def visit_TryExcept(self, node):
- if node.body:
- self.visit_sequence(node.body)
- if node.handlers:
- self.visit_sequence(node.handlers)
- if node.orelse:
- self.visit_sequence(node.orelse)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.handlers)
+ self.visit_sequence(node.orelse)
def visit_TryFinally(self, node):
- if node.body:
- self.visit_sequence(node.body)
- if node.finalbody:
- self.visit_sequence(node.finalbody)
+ self.visit_sequence(node.body)
+ self.visit_sequence(node.finalbody)
def visit_Assert(self, node):
node.test.walkabout(self)
@@ -2782,12 +2760,10 @@
node.msg.walkabout(self)
def visit_Import(self, node):
- if node.names:
- self.visit_sequence(node.names)
+ self.visit_sequence(node.names)
def visit_ImportFrom(self, node):
- if node.names:
- self.visit_sequence(node.names)
+ self.visit_sequence(node.names)
def visit_Exec(self, node):
node.body.walkabout(self)
@@ -2812,8 +2788,7 @@
pass
def visit_BoolOp(self, node):
- if node.values:
- self.visit_sequence(node.values)
+ self.visit_sequence(node.values)
def visit_BinOp(self, node):
node.left.walkabout(self)
@@ -2832,35 +2807,28 @@
node.orelse.walkabout(self)
def visit_Dict(self, node):
- if node.keys:
- self.visit_sequence(node.keys)
- if node.values:
- self.visit_sequence(node.values)
+ self.visit_sequence(node.keys)
+ self.visit_sequence(node.values)
def visit_Set(self, node):
- if node.elts:
- self.visit_sequence(node.elts)
+ self.visit_sequence(node.elts)
def visit_ListComp(self, node):
node.elt.walkabout(self)
- if node.generators:
- self.visit_sequence(node.generators)
+ self.visit_sequence(node.generators)
def visit_SetComp(self, node):
node.elt.walkabout(self)
- if node.generators:
- self.visit_sequence(node.generators)
+ self.visit_sequence(node.generators)
def visit_DictComp(self, node):
node.key.walkabout(self)
node.value.walkabout(self)
- if node.generators:
- self.visit_sequence(node.generators)
+ self.visit_sequence(node.generators)
def visit_GeneratorExp(self, node):
node.elt.walkabout(self)
- if node.generators:
- self.visit_sequence(node.generators)
+ self.visit_sequence(node.generators)
def visit_Yield(self, node):
if node.value:
@@ -2868,15 +2836,12 @@
def visit_Compare(self, node):
node.left.walkabout(self)
- if node.comparators:
- self.visit_sequence(node.comparators)
+ self.visit_sequence(node.comparators)
def visit_Call(self, node):
node.func.walkabout(self)
- if node.args:
- self.visit_sequence(node.args)
- if node.keywords:
- self.visit_sequence(node.keywords)
+ self.visit_sequence(node.args)
+ self.visit_sequence(node.keywords)
if node.starargs:
node.starargs.walkabout(self)
if node.kwargs:
@@ -2902,12 +2867,10 @@
pass
def visit_List(self, node):
- if node.elts:
- self.visit_sequence(node.elts)
+ self.visit_sequence(node.elts)
def visit_Tuple(self, node):
- if node.elts:
- self.visit_sequence(node.elts)
+ self.visit_sequence(node.elts)
def visit_Const(self, node):
pass
@@ -2924,8 +2887,7 @@
node.step.walkabout(self)
def visit_ExtSlice(self, node):
- if node.dims:
- self.visit_sequence(node.dims)
+ self.visit_sequence(node.dims)
def visit_Index(self, node):
node.value.walkabout(self)
@@ -2933,22 +2895,18 @@
def visit_comprehension(self, node):
node.target.walkabout(self)
node.iter.walkabout(self)
- if node.ifs:
- self.visit_sequence(node.ifs)
+ self.visit_sequence(node.ifs)
def visit_ExceptHandler(self, node):
if node.type:
node.type.walkabout(self)
if node.name:
node.name.walkabout(self)
- if node.body:
- self.visit_sequence(node.body)
+ self.visit_sequence(node.body)
def visit_arguments(self, node):
- if node.args:
- self.visit_sequence(node.args)
- if node.defaults:
- self.visit_sequence(node.defaults)
+ self.visit_sequence(node.args)
+ self.visit_sequence(node.defaults)
def visit_keyword(self, node):
node.value.walkabout(self)
@@ -3069,6 +3027,7 @@
raise
w_self.setdictvalue(space, 'body', w_new_value)
return
+ w_self.deldictvalue(space, 'body')
w_self.initialization_state |= 1
_Expression_field_unroller = unrolling_iterable(['body'])
@@ -3157,6 +3116,7 @@
raise
w_self.setdictvalue(space, 'lineno', w_new_value)
return
+ w_self.deldictvalue(space, 'lineno')
w_self.initialization_state |= w_self._lineno_mask
def stmt_get_col_offset(space, w_self):
@@ -3178,6 +3138,7 @@
raise
w_self.setdictvalue(space, 'col_offset', w_new_value)
return
+ w_self.deldictvalue(space, 'col_offset')
w_self.initialization_state |= w_self._col_offset_mask
stmt.typedef = typedef.TypeDef("stmt",
@@ -3208,6 +3169,7 @@
raise
w_self.setdictvalue(space, 'name', w_new_value)
return
+ w_self.deldictvalue(space, 'name')
w_self.initialization_state |= 1
def FunctionDef_get_args(space, w_self):
@@ -3229,6 +3191,7 @@
raise
w_self.setdictvalue(space, 'args', w_new_value)
return
+ w_self.deldictvalue(space, 'args')
w_self.initialization_state |= 2
def FunctionDef_get_body(space, w_self):
@@ -3315,6 +3278,7 @@
raise
w_self.setdictvalue(space, 'name', w_new_value)
return
+ w_self.deldictvalue(space, 'name')
w_self.initialization_state |= 1
def ClassDef_get_bases(space, w_self):
@@ -3420,6 +3384,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
_Return_field_unroller = unrolling_iterable(['value'])
@@ -3526,6 +3491,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 2
_Assign_field_unroller = unrolling_iterable(['targets', 'value'])
@@ -3573,6 +3539,7 @@
raise
w_self.setdictvalue(space, 'target', w_new_value)
return
+ w_self.deldictvalue(space, 'target')
w_self.initialization_state |= 1
def AugAssign_get_op(space, w_self):
@@ -3590,13 +3557,13 @@
try:
obj = space.interp_w(operator, w_new_value)
w_self.op = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'op', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'op', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'op', w_new_value)
w_self.initialization_state |= 2
def AugAssign_get_value(space, w_self):
@@ -3618,6 +3585,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 4
_AugAssign_field_unroller = unrolling_iterable(['target', 'op', 'value'])
@@ -3665,6 +3633,7 @@
raise
w_self.setdictvalue(space, 'dest', w_new_value)
return
+ w_self.deldictvalue(space, 'dest')
w_self.initialization_state |= 1
def Print_get_values(space, w_self):
@@ -3704,6 +3673,7 @@
raise
w_self.setdictvalue(space, 'nl', w_new_value)
return
+ w_self.deldictvalue(space, 'nl')
w_self.initialization_state |= 4
_Print_field_unroller = unrolling_iterable(['dest', 'values', 'nl'])
@@ -3752,6 +3722,7 @@
raise
w_self.setdictvalue(space, 'target', w_new_value)
return
+ w_self.deldictvalue(space, 'target')
w_self.initialization_state |= 1
def For_get_iter(space, w_self):
@@ -3773,6 +3744,7 @@
raise
w_self.setdictvalue(space, 'iter', w_new_value)
return
+ w_self.deldictvalue(space, 'iter')
w_self.initialization_state |= 2
def For_get_body(space, w_self):
@@ -3859,6 +3831,7 @@
raise
w_self.setdictvalue(space, 'test', w_new_value)
return
+ w_self.deldictvalue(space, 'test')
w_self.initialization_state |= 1
def While_get_body(space, w_self):
@@ -3944,6 +3917,7 @@
raise
w_self.setdictvalue(space, 'test', w_new_value)
return
+ w_self.deldictvalue(space, 'test')
w_self.initialization_state |= 1
def If_get_body(space, w_self):
@@ -4029,6 +4003,7 @@
raise
w_self.setdictvalue(space, 'context_expr', w_new_value)
return
+ w_self.deldictvalue(space, 'context_expr')
w_self.initialization_state |= 1
def With_get_optional_vars(space, w_self):
@@ -4050,6 +4025,7 @@
raise
w_self.setdictvalue(space, 'optional_vars', w_new_value)
return
+ w_self.deldictvalue(space, 'optional_vars')
w_self.initialization_state |= 2
def With_get_body(space, w_self):
@@ -4116,6 +4092,7 @@
raise
w_self.setdictvalue(space, 'type', w_new_value)
return
+ w_self.deldictvalue(space, 'type')
w_self.initialization_state |= 1
def Raise_get_inst(space, w_self):
@@ -4137,6 +4114,7 @@
raise
w_self.setdictvalue(space, 'inst', w_new_value)
return
+ w_self.deldictvalue(space, 'inst')
w_self.initialization_state |= 2
def Raise_get_tback(space, w_self):
@@ -4158,6 +4136,7 @@
raise
w_self.setdictvalue(space, 'tback', w_new_value)
return
+ w_self.deldictvalue(space, 'tback')
w_self.initialization_state |= 4
_Raise_field_unroller = unrolling_iterable(['type', 'inst', 'tback'])
@@ -4351,6 +4330,7 @@
raise
w_self.setdictvalue(space, 'test', w_new_value)
return
+ w_self.deldictvalue(space, 'test')
w_self.initialization_state |= 1
def Assert_get_msg(space, w_self):
@@ -4372,6 +4352,7 @@
raise
w_self.setdictvalue(space, 'msg', w_new_value)
return
+ w_self.deldictvalue(space, 'msg')
w_self.initialization_state |= 2
_Assert_field_unroller = unrolling_iterable(['test', 'msg'])
@@ -4464,6 +4445,7 @@
raise
w_self.setdictvalue(space, 'module', w_new_value)
return
+ w_self.deldictvalue(space, 'module')
w_self.initialization_state |= 1
def ImportFrom_get_names(space, w_self):
@@ -4503,6 +4485,7 @@
raise
w_self.setdictvalue(space, 'level', w_new_value)
return
+ w_self.deldictvalue(space, 'level')
w_self.initialization_state |= 4
_ImportFrom_field_unroller = unrolling_iterable(['module', 'names', 'level'])
@@ -4551,6 +4534,7 @@
raise
w_self.setdictvalue(space, 'body', w_new_value)
return
+ w_self.deldictvalue(space, 'body')
w_self.initialization_state |= 1
def Exec_get_globals(space, w_self):
@@ -4572,6 +4556,7 @@
raise
w_self.setdictvalue(space, 'globals', w_new_value)
return
+ w_self.deldictvalue(space, 'globals')
w_self.initialization_state |= 2
def Exec_get_locals(space, w_self):
@@ -4593,6 +4578,7 @@
raise
w_self.setdictvalue(space, 'locals', w_new_value)
return
+ w_self.deldictvalue(space, 'locals')
w_self.initialization_state |= 4
_Exec_field_unroller = unrolling_iterable(['body', 'globals', 'locals'])
@@ -4683,6 +4669,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
_Expr_field_unroller = unrolling_iterable(['value'])
@@ -4779,6 +4766,7 @@
raise
w_self.setdictvalue(space, 'lineno', w_new_value)
return
+ w_self.deldictvalue(space, 'lineno')
w_self.initialization_state |= w_self._lineno_mask
def expr_get_col_offset(space, w_self):
@@ -4800,6 +4788,7 @@
raise
w_self.setdictvalue(space, 'col_offset', w_new_value)
return
+ w_self.deldictvalue(space, 'col_offset')
w_self.initialization_state |= w_self._col_offset_mask
expr.typedef = typedef.TypeDef("expr",
@@ -4826,13 +4815,13 @@
try:
obj = space.interp_w(boolop, w_new_value)
w_self.op = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'op', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'op', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'op', w_new_value)
w_self.initialization_state |= 1
def BoolOp_get_values(space, w_self):
@@ -4898,6 +4887,7 @@
raise
w_self.setdictvalue(space, 'left', w_new_value)
return
+ w_self.deldictvalue(space, 'left')
w_self.initialization_state |= 1
def BinOp_get_op(space, w_self):
@@ -4915,13 +4905,13 @@
try:
obj = space.interp_w(operator, w_new_value)
w_self.op = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'op', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'op', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'op', w_new_value)
w_self.initialization_state |= 2
def BinOp_get_right(space, w_self):
@@ -4943,6 +4933,7 @@
raise
w_self.setdictvalue(space, 'right', w_new_value)
return
+ w_self.deldictvalue(space, 'right')
w_self.initialization_state |= 4
_BinOp_field_unroller = unrolling_iterable(['left', 'op', 'right'])
@@ -4986,13 +4977,13 @@
try:
obj = space.interp_w(unaryop, w_new_value)
w_self.op = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'op', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'op', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'op', w_new_value)
w_self.initialization_state |= 1
def UnaryOp_get_operand(space, w_self):
@@ -5014,6 +5005,7 @@
raise
w_self.setdictvalue(space, 'operand', w_new_value)
return
+ w_self.deldictvalue(space, 'operand')
w_self.initialization_state |= 2
_UnaryOp_field_unroller = unrolling_iterable(['op', 'operand'])
@@ -5060,6 +5052,7 @@
raise
w_self.setdictvalue(space, 'args', w_new_value)
return
+ w_self.deldictvalue(space, 'args')
w_self.initialization_state |= 1
def Lambda_get_body(space, w_self):
@@ -5081,6 +5074,7 @@
raise
w_self.setdictvalue(space, 'body', w_new_value)
return
+ w_self.deldictvalue(space, 'body')
w_self.initialization_state |= 2
_Lambda_field_unroller = unrolling_iterable(['args', 'body'])
@@ -5127,6 +5121,7 @@
raise
w_self.setdictvalue(space, 'test', w_new_value)
return
+ w_self.deldictvalue(space, 'test')
w_self.initialization_state |= 1
def IfExp_get_body(space, w_self):
@@ -5148,6 +5143,7 @@
raise
w_self.setdictvalue(space, 'body', w_new_value)
return
+ w_self.deldictvalue(space, 'body')
w_self.initialization_state |= 2
def IfExp_get_orelse(space, w_self):
@@ -5169,6 +5165,7 @@
raise
w_self.setdictvalue(space, 'orelse', w_new_value)
return
+ w_self.deldictvalue(space, 'orelse')
w_self.initialization_state |= 4
_IfExp_field_unroller = unrolling_iterable(['test', 'body', 'orelse'])
@@ -5322,6 +5319,7 @@
raise
w_self.setdictvalue(space, 'elt', w_new_value)
return
+ w_self.deldictvalue(space, 'elt')
w_self.initialization_state |= 1
def ListComp_get_generators(space, w_self):
@@ -5387,6 +5385,7 @@
raise
w_self.setdictvalue(space, 'elt', w_new_value)
return
+ w_self.deldictvalue(space, 'elt')
w_self.initialization_state |= 1
def SetComp_get_generators(space, w_self):
@@ -5452,6 +5451,7 @@
raise
w_self.setdictvalue(space, 'key', w_new_value)
return
+ w_self.deldictvalue(space, 'key')
w_self.initialization_state |= 1
def DictComp_get_value(space, w_self):
@@ -5473,6 +5473,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 2
def DictComp_get_generators(space, w_self):
@@ -5539,6 +5540,7 @@
raise
w_self.setdictvalue(space, 'elt', w_new_value)
return
+ w_self.deldictvalue(space, 'elt')
w_self.initialization_state |= 1
def GeneratorExp_get_generators(space, w_self):
@@ -5604,6 +5606,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
_Yield_field_unroller = unrolling_iterable(['value'])
@@ -5649,6 +5652,7 @@
raise
w_self.setdictvalue(space, 'left', w_new_value)
return
+ w_self.deldictvalue(space, 'left')
w_self.initialization_state |= 1
def Compare_get_ops(space, w_self):
@@ -5734,6 +5738,7 @@
raise
w_self.setdictvalue(space, 'func', w_new_value)
return
+ w_self.deldictvalue(space, 'func')
w_self.initialization_state |= 1
def Call_get_args(space, w_self):
@@ -5791,6 +5796,7 @@
raise
w_self.setdictvalue(space, 'starargs', w_new_value)
return
+ w_self.deldictvalue(space, 'starargs')
w_self.initialization_state |= 8
def Call_get_kwargs(space, w_self):
@@ -5812,6 +5818,7 @@
raise
w_self.setdictvalue(space, 'kwargs', w_new_value)
return
+ w_self.deldictvalue(space, 'kwargs')
w_self.initialization_state |= 16
_Call_field_unroller = unrolling_iterable(['func', 'args', 'keywords', 'starargs', 'kwargs'])
@@ -5863,6 +5870,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
_Repr_field_unroller = unrolling_iterable(['value'])
@@ -5908,6 +5916,7 @@
raise
w_self.setdictvalue(space, 'n', w_new_value)
return
+ w_self.deldictvalue(space, 'n')
w_self.initialization_state |= 1
_Num_field_unroller = unrolling_iterable(['n'])
@@ -5953,6 +5962,7 @@
raise
w_self.setdictvalue(space, 's', w_new_value)
return
+ w_self.deldictvalue(space, 's')
w_self.initialization_state |= 1
_Str_field_unroller = unrolling_iterable(['s'])
@@ -5998,6 +6008,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
def Attribute_get_attr(space, w_self):
@@ -6019,6 +6030,7 @@
raise
w_self.setdictvalue(space, 'attr', w_new_value)
return
+ w_self.deldictvalue(space, 'attr')
w_self.initialization_state |= 2
def Attribute_get_ctx(space, w_self):
@@ -6036,13 +6048,13 @@
try:
obj = space.interp_w(expr_context, w_new_value)
w_self.ctx = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'ctx', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'ctx', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'ctx', w_new_value)
w_self.initialization_state |= 4
_Attribute_field_unroller = unrolling_iterable(['value', 'attr', 'ctx'])
@@ -6090,6 +6102,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
def Subscript_get_slice(space, w_self):
@@ -6111,6 +6124,7 @@
raise
w_self.setdictvalue(space, 'slice', w_new_value)
return
+ w_self.deldictvalue(space, 'slice')
w_self.initialization_state |= 2
def Subscript_get_ctx(space, w_self):
@@ -6128,13 +6142,13 @@
try:
obj = space.interp_w(expr_context, w_new_value)
w_self.ctx = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'ctx', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'ctx', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'ctx', w_new_value)
w_self.initialization_state |= 4
_Subscript_field_unroller = unrolling_iterable(['value', 'slice', 'ctx'])
@@ -6182,6 +6196,7 @@
raise
w_self.setdictvalue(space, 'id', w_new_value)
return
+ w_self.deldictvalue(space, 'id')
w_self.initialization_state |= 1
def Name_get_ctx(space, w_self):
@@ -6199,13 +6214,13 @@
try:
obj = space.interp_w(expr_context, w_new_value)
w_self.ctx = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'ctx', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'ctx', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'ctx', w_new_value)
w_self.initialization_state |= 2
_Name_field_unroller = unrolling_iterable(['id', 'ctx'])
@@ -6266,13 +6281,13 @@
try:
obj = space.interp_w(expr_context, w_new_value)
w_self.ctx = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'ctx', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'ctx', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'ctx', w_new_value)
w_self.initialization_state |= 2
_List_field_unroller = unrolling_iterable(['elts', 'ctx'])
@@ -6334,13 +6349,13 @@
try:
obj = space.interp_w(expr_context, w_new_value)
w_self.ctx = obj.to_simple_int(space)
- # need to save the original object too
- w_self.setdictvalue(space, 'ctx', w_new_value)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
w_self.setdictvalue(space, 'ctx', w_new_value)
return
+ # need to save the original object too
+ w_self.setdictvalue(space, 'ctx', w_new_value)
w_self.initialization_state |= 2
_Tuple_field_unroller = unrolling_iterable(['elts', 'ctx'])
@@ -6388,6 +6403,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
_Const_field_unroller = unrolling_iterable(['value'])
@@ -6506,6 +6522,7 @@
raise
w_self.setdictvalue(space, 'lower', w_new_value)
return
+ w_self.deldictvalue(space, 'lower')
w_self.initialization_state |= 1
def Slice_get_upper(space, w_self):
@@ -6527,6 +6544,7 @@
raise
w_self.setdictvalue(space, 'upper', w_new_value)
return
+ w_self.deldictvalue(space, 'upper')
w_self.initialization_state |= 2
def Slice_get_step(space, w_self):
@@ -6548,6 +6566,7 @@
raise
w_self.setdictvalue(space, 'step', w_new_value)
return
+ w_self.deldictvalue(space, 'step')
w_self.initialization_state |= 4
_Slice_field_unroller = unrolling_iterable(['lower', 'upper', 'step'])
@@ -6638,6 +6657,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 1
_Index_field_unroller = unrolling_iterable(['value'])
@@ -6907,6 +6927,7 @@
raise
w_self.setdictvalue(space, 'target', w_new_value)
return
+ w_self.deldictvalue(space, 'target')
w_self.initialization_state |= 1
def comprehension_get_iter(space, w_self):
@@ -6928,6 +6949,7 @@
raise
w_self.setdictvalue(space, 'iter', w_new_value)
return
+ w_self.deldictvalue(space, 'iter')
w_self.initialization_state |= 2
def comprehension_get_ifs(space, w_self):
@@ -6994,6 +7016,7 @@
raise
w_self.setdictvalue(space, 'lineno', w_new_value)
return
+ w_self.deldictvalue(space, 'lineno')
w_self.initialization_state |= w_self._lineno_mask
def excepthandler_get_col_offset(space, w_self):
@@ -7015,6 +7038,7 @@
raise
w_self.setdictvalue(space, 'col_offset', w_new_value)
return
+ w_self.deldictvalue(space, 'col_offset')
w_self.initialization_state |= w_self._col_offset_mask
excepthandler.typedef = typedef.TypeDef("excepthandler",
@@ -7045,6 +7069,7 @@
raise
w_self.setdictvalue(space, 'type', w_new_value)
return
+ w_self.deldictvalue(space, 'type')
w_self.initialization_state |= 1
def ExceptHandler_get_name(space, w_self):
@@ -7066,6 +7091,7 @@
raise
w_self.setdictvalue(space, 'name', w_new_value)
return
+ w_self.deldictvalue(space, 'name')
w_self.initialization_state |= 2
def ExceptHandler_get_body(space, w_self):
@@ -7153,6 +7179,7 @@
raise
w_self.setdictvalue(space, 'vararg', w_new_value)
return
+ w_self.deldictvalue(space, 'vararg')
w_self.initialization_state |= 2
def arguments_get_kwarg(space, w_self):
@@ -7177,6 +7204,7 @@
raise
w_self.setdictvalue(space, 'kwarg', w_new_value)
return
+ w_self.deldictvalue(space, 'kwarg')
w_self.initialization_state |= 4
def arguments_get_defaults(space, w_self):
@@ -7245,6 +7273,7 @@
raise
w_self.setdictvalue(space, 'arg', w_new_value)
return
+ w_self.deldictvalue(space, 'arg')
w_self.initialization_state |= 1
def keyword_get_value(space, w_self):
@@ -7266,6 +7295,7 @@
raise
w_self.setdictvalue(space, 'value', w_new_value)
return
+ w_self.deldictvalue(space, 'value')
w_self.initialization_state |= 2
_keyword_field_unroller = unrolling_iterable(['arg', 'value'])
@@ -7312,6 +7342,7 @@
raise
w_self.setdictvalue(space, 'name', w_new_value)
return
+ w_self.deldictvalue(space, 'name')
w_self.initialization_state |= 1
def alias_get_asname(space, w_self):
@@ -7336,6 +7367,7 @@
raise
w_self.setdictvalue(space, 'asname', w_new_value)
return
+ w_self.deldictvalue(space, 'asname')
w_self.initialization_state |= 2
_alias_field_unroller = unrolling_iterable(['name', 'asname'])
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -295,15 +295,11 @@
def visit_FunctionDef(self, func):
self.update_position(func.lineno, True)
# Load decorators first, but apply them after the function is created.
- if func.decorator_list:
- self.visit_sequence(func.decorator_list)
+ self.visit_sequence(func.decorator_list)
args = func.args
assert isinstance(args, ast.arguments)
- if args.defaults:
- self.visit_sequence(args.defaults)
- num_defaults = len(args.defaults)
- else:
- num_defaults = 0
+ self.visit_sequence(args.defaults)
+ num_defaults = len(args.defaults) if args.defaults is not None else 0
code = self.sub_scope(FunctionCodeGenerator, func.name, func,
func.lineno)
self._make_function(code, num_defaults)
@@ -317,24 +313,17 @@
self.update_position(lam.lineno)
args = lam.args
assert isinstance(args, ast.arguments)
- if args.defaults:
- self.visit_sequence(args.defaults)
- default_count = len(args.defaults)
- else:
- default_count = 0
+ self.visit_sequence(args.defaults)
+ default_count = len(args.defaults) if args.defaults is not None else 0
code = self.sub_scope(LambdaCodeGenerator, "<lambda>", lam, lam.lineno)
self._make_function(code, default_count)
def visit_ClassDef(self, cls):
self.update_position(cls.lineno, True)
- if cls.decorator_list:
- self.visit_sequence(cls.decorator_list)
+ self.visit_sequence(cls.decorator_list)
self.load_const(self.space.wrap(cls.name))
- if cls.bases:
- bases_count = len(cls.bases)
- self.visit_sequence(cls.bases)
- else:
- bases_count = 0
+ self.visit_sequence(cls.bases)
+ bases_count = len(cls.bases) if cls.bases is not None else 0
self.emit_op_arg(ops.BUILD_TUPLE, bases_count)
code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno)
self._make_function(code, 0)
@@ -446,8 +435,7 @@
end = self.new_block()
test_constant = if_.test.as_constant_truth(self.space)
if test_constant == optimize.CONST_FALSE:
- if if_.orelse:
- self.visit_sequence(if_.orelse)
+ self.visit_sequence(if_.orelse)
elif test_constant == optimize.CONST_TRUE:
self.visit_sequence(if_.body)
else:
@@ -515,16 +503,14 @@
self.use_next_block(cleanup)
self.emit_op(ops.POP_BLOCK)
self.pop_frame_block(F_BLOCK_LOOP, start)
- if fr.orelse:
- self.visit_sequence(fr.orelse)
+ self.visit_sequence(fr.orelse)
self.use_next_block(end)
def visit_While(self, wh):
self.update_position(wh.lineno, True)
test_constant = wh.test.as_constant_truth(self.space)
if test_constant == optimize.CONST_FALSE:
- if wh.orelse:
- self.visit_sequence(wh.orelse)
+ self.visit_sequence(wh.orelse)
else:
end = self.new_block()
anchor = None
@@ -544,8 +530,7 @@
self.use_next_block(anchor)
self.emit_op(ops.POP_BLOCK)
self.pop_frame_block(F_BLOCK_LOOP, loop)
- if wh.orelse:
- self.visit_sequence(wh.orelse)
+ self.visit_sequence(wh.orelse)
self.use_next_block(end)
def visit_TryExcept(self, te):
@@ -581,8 +566,7 @@
self.use_next_block(next_except)
self.emit_op(ops.END_FINALLY)
self.use_next_block(otherwise)
- if te.orelse:
- self.visit_sequence(te.orelse)
+ self.visit_sequence(te.orelse)
self.use_next_block(end)
def visit_TryFinally(self, tf):
@@ -893,27 +877,19 @@
def visit_Tuple(self, tup):
self.update_position(tup.lineno)
- if tup.elts:
- elt_count = len(tup.elts)
- else:
- elt_count = 0
+ elt_count = len(tup.elts) if tup.elts is not None else 0
if tup.ctx == ast.Store:
self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count)
- if elt_count:
- self.visit_sequence(tup.elts)
+ self.visit_sequence(tup.elts)
if tup.ctx == ast.Load:
self.emit_op_arg(ops.BUILD_TUPLE, elt_count)
def visit_List(self, l):
self.update_position(l.lineno)
- if l.elts:
- elt_count = len(l.elts)
- else:
- elt_count = 0
+ elt_count = len(l.elts) if l.elts is not None else 0
if l.ctx == ast.Store:
self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count)
- if elt_count:
- self.visit_sequence(l.elts)
+ self.visit_sequence(l.elts)
if l.ctx == ast.Load:
self.emit_op_arg(ops.BUILD_LIST, elt_count)
@@ -944,11 +920,9 @@
if self._optimize_method_call(call):
return
call.func.walkabout(self)
- arg = 0
+ arg = len(call.args) if call.args is not None else 0
call_type = 0
- if call.args:
- arg = len(call.args)
- self.visit_sequence(call.args)
+ self.visit_sequence(call.args)
if call.keywords:
self.visit_sequence(call.keywords)
arg |= len(call.keywords) << 8
@@ -984,16 +958,10 @@
assert isinstance(attr_lookup, ast.Attribute)
attr_lookup.value.walkabout(self)
self.emit_op_name(ops.LOOKUP_METHOD, self.names, attr_lookup.attr)
- if call.args:
- self.visit_sequence(call.args)
- arg_count = len(call.args)
- else:
- arg_count = 0
- if call.keywords:
- self.visit_sequence(call.keywords)
- kwarg_count = len(call.keywords)
- else:
- kwarg_count = 0
+ self.visit_sequence(call.args)
+ arg_count = len(call.args) if call.args is not None else 0
+ self.visit_sequence(call.keywords)
+ kwarg_count = len(call.keywords) if call.keywords is not None else 0
self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count)
return True
@@ -1251,7 +1219,10 @@
def _compile(self, func):
assert isinstance(func, ast.FunctionDef)
# If there's a docstring, store it as the first constant.
- doc_expr = self.possible_docstring(func.body[0])
+ if func.body:
+ doc_expr = self.possible_docstring(func.body[0])
+ else:
+ doc_expr = None
if doc_expr is not None:
self.add_const(doc_expr.s)
start = 1
@@ -1263,8 +1234,9 @@
if args.args:
self._handle_nested_args(args.args)
self.argcount = len(args.args)
- for i in range(start, len(func.body)):
- func.body[i].walkabout(self)
+ if func.body:
+ for i in range(start, len(func.body)):
+ func.body[i].walkabout(self)
class LambdaCodeGenerator(AbstractFunctionCodeGenerator):
diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py
--- a/pypy/interpreter/astcompiler/misc.py
+++ b/pypy/interpreter/astcompiler/misc.py
@@ -27,9 +27,10 @@
_emit_syntax_warning(space, w_msg, w_filename, w_lineno, w_offset)
-def parse_future(tree):
+def parse_future(tree, feature_flags):
future_lineno = 0
future_column = 0
+ flags = 0
have_docstring = False
body = None
if isinstance(tree, ast.Module):
@@ -37,7 +38,7 @@
elif isinstance(tree, ast.Interactive):
body = tree.body
if body is None:
- return 0, 0
+ return 0, 0, 0
for stmt in body:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
if have_docstring:
@@ -48,11 +49,16 @@
if stmt.module == "__future__":
future_lineno = stmt.lineno
future_column = stmt.col_offset
+ for alias in stmt.names:
+ assert isinstance(alias, ast.alias)
+ # If this is an invalid flag, it will be caught later in
+ # codegen.py.
+ flags |= feature_flags.get(alias.name, 0)
else:
break
else:
break
- return future_lineno, future_column
+ return flags, future_lineno, future_column
class ForbiddenNameAssignment(Exception):
diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -356,10 +356,8 @@
# Function defaults and decorators happen in the outer scope.
args = func.args
assert isinstance(args, ast.arguments)
- if args.defaults:
- self.visit_sequence(args.defaults)
- if func.decorator_list:
- self.visit_sequence(func.decorator_list)
+ self.visit_sequence(args.defaults)
+ self.visit_sequence(func.decorator_list)
new_scope = FunctionScope(func.name, func.lineno, func.col_offset)
self.push_scope(new_scope, func)
func.args.walkabout(self)
@@ -372,10 +370,8 @@
def visit_ClassDef(self, clsdef):
self.note_symbol(clsdef.name, SYM_ASSIGNED)
- if clsdef.bases:
- self.visit_sequence(clsdef.bases)
- if clsdef.decorator_list:
- self.visit_sequence(clsdef.decorator_list)
+ self.visit_sequence(clsdef.bases)
+ self.visit_sequence(clsdef.decorator_list)
self.push_scope(ClassScope(clsdef), clsdef)
self.visit_sequence(clsdef.body)
self.pop_scope()
@@ -431,8 +427,7 @@
def visit_Lambda(self, lamb):
args = lamb.args
assert isinstance(args, ast.arguments)
- if args.defaults:
- self.visit_sequence(args.defaults)
+ self.visit_sequence(args.defaults)
new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset)
self.push_scope(new_scope, lamb)
lamb.args.walkabout(self)
@@ -447,8 +442,7 @@
self.push_scope(new_scope, node)
self.implicit_arg(0)
outer.target.walkabout(self)
- if outer.ifs:
- self.visit_sequence(outer.ifs)
+ self.visit_sequence(outer.ifs)
self.visit_sequence(comps[1:])
for item in list(consider):
item.walkabout(self)
diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py
--- a/pypy/interpreter/astcompiler/tools/asdl_py.py
+++ b/pypy/interpreter/astcompiler/tools/asdl_py.py
@@ -221,8 +221,9 @@
self.emit("class ASTVisitor(object):")
self.emit("")
self.emit("def visit_sequence(self, seq):", 1)
- self.emit("for node in seq:", 2)
- self.emit("node.walkabout(self)", 3)
+ self.emit("if seq is not None:", 2)
+ self.emit("for node in seq:", 3)
+ self.emit("node.walkabout(self)", 4)
self.emit("")
self.emit("def default_visitor(self, node):", 1)
self.emit("raise NodeVisitorNotImplemented", 2)
@@ -280,15 +281,13 @@
def visitField(self, field):
if field.type.value not in asdl.builtin_types and \
field.type.value not in self.data.simple_types:
- if field.seq or field.opt:
+ level = 2
+ template = "node.%s.walkabout(self)"
+ if field.seq:
+ template = "self.visit_sequence(node.%s)"
+ elif field.opt:
self.emit("if node.%s:" % (field.name,), 2)
level = 3
- else:
- level = 2
- if field.seq:
- template = "self.visit_sequence(node.%s)"
- else:
- template = "node.%s.walkabout(self)"
self.emit(template % (field.name,), level)
return True
return False
@@ -446,6 +445,7 @@
if field.seq:
self.emit("w_self.w_%s = w_new_value" % (field.name,), 1)
else:
+ save_original_object = False
self.emit("try:", 1)
if field.type.value not in asdl.builtin_types:
# These are always other AST nodes.
@@ -454,9 +454,7 @@
(field.type,), 2)
self.emit("w_self.%s = obj.to_simple_int(space)" %
(field.name,), 2)
- self.emit("# need to save the original object too", 2)
- self.emit("w_self.setdictvalue(space, '%s', w_new_value)"
- % (field.name,), 2)
+ save_original_object = True
else:
config = (field.name, field.type, repr(field.opt))
self.emit("w_self.%s = space.interp_w(%s, w_new_value, %s)" %
@@ -480,6 +478,12 @@
self.emit(" w_self.setdictvalue(space, '%s', w_new_value)"
% (field.name,), 1)
self.emit(" return", 1)
+ if save_original_object:
+ self.emit("# need to save the original object too", 1)
+ self.emit("w_self.setdictvalue(space, '%s', w_new_value)"
+ % (field.name,), 1)
+ else:
+ self.emit("w_self.deldictvalue(space, '%s')" %(field.name,), 1)
self.emit("w_self.initialization_state |= %s" % (flag,), 1)
self.emit("")
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -44,11 +44,11 @@
return True
return False
- def deldictvalue(self, space, w_name):
+ def deldictvalue(self, space, attr):
w_dict = self.getdict(space)
if w_dict is not None:
try:
- space.delitem(w_dict, w_name)
+ space.delitem(w_dict, space.wrap(attr))
return True
except OperationError, ex:
if not ex.match(space, space.w_KeyError):
@@ -130,6 +130,9 @@
raise operationerrfmt(space.w_TypeError,
"cannot create weak reference to '%s' object", typename)
+ def delweakref(self):
+ pass
+
def clear_all_weakrefs(self):
"""Call this at the beginning of interp-level __del__() methods
in subclasses. It ensures that weakrefs (if any) are cleared
@@ -143,29 +146,28 @@
# app-level, e.g. a user-defined __del__(), and this code
# tries to use weakrefs again, it won't reuse the broken
# (already-cleared) weakrefs from this lifeline.
- self.setweakref(lifeline.space, None)
+ self.delweakref()
lifeline.clear_all_weakrefs()
- __already_enqueued_for_destruction = False
+ __already_enqueued_for_destruction = ()
- def _enqueue_for_destruction(self, space, call_user_del=True):
+ def enqueue_for_destruction(self, space, callback, descrname):
"""Put the object in the destructor queue of the space.
- At a later, safe point in time, UserDelAction will use
- space.userdel() to call the object's app-level __del__ method.
+ At a later, safe point in time, UserDelAction will call
+ callback(self). If that raises OperationError, prints it
+ to stderr with the descrname string.
+
+ Note that 'callback' will usually need to start with:
+ assert isinstance(self, W_SpecificClass)
"""
# this function always resurect the object, so when
# running on top of CPython we must manually ensure that
# we enqueue it only once
if not we_are_translated():
- if self.__already_enqueued_for_destruction:
+ if callback in self.__already_enqueued_for_destruction:
return
- self.__already_enqueued_for_destruction = True
- self.clear_all_weakrefs()
- if call_user_del:
- space.user_del_action.register_dying_object(self)
-
- def _call_builtin_destructor(self):
- pass # method overridden in typedef.py
+ self.__already_enqueued_for_destruction += (callback,)
+ space.user_del_action.register_callback(self, callback, descrname)
# hooks that the mapdict implementations needs:
def _get_mapdict_map(self):
@@ -237,7 +239,7 @@
class ObjSpace(object):
"""Base class for the interpreter-level implementations of object spaces.
- http://codespeak.net/pypy/dist/pypy/doc/objspace.html"""
+ http://pypy.readthedocs.org/en/latest/objspace.html"""
full_exceptions = True # full support for exceptions (normalization & more)
@@ -925,6 +927,9 @@
return self.w_True
return self.w_False
+ def issequence_w(self, w_obj):
+ return (self.findattr(w_obj, self.wrap("__getitem__")) is not None)
+
def isinstance_w(self, w_obj, w_type):
return self.is_true(self.isinstance(w_obj, w_type))
@@ -1279,6 +1284,17 @@
self.wrap("expected a 32-bit integer"))
return value
+ def truncatedint(self, w_obj):
+ # Like space.gateway_int_w(), but return the integer truncated
+ # instead of raising OverflowError. For obscure cases only.
+ try:
+ return self.int_w(w_obj)
+ except OperationError, e:
+ if not e.match(self, self.w_OverflowError):
+ raise
+ from pypy.rlib.rarithmetic import intmask
+ return intmask(self.bigint_w(w_obj).uintmask())
+
def c_filedescriptor_w(self, w_fd):
# This is only used sometimes in CPython, e.g. for os.fsync() but
# not os.close(). It's likely designed for 'select'. It's irregular
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -189,7 +189,7 @@
if space.is_w(w_value, space.w_None):
# raise Type: we assume we have to instantiate Type
w_value = space.call_function(w_type)
- w_type = space.exception_getclass(w_value)
+ w_type = self._exception_getclass(space, w_value)
else:
w_valuetype = space.exception_getclass(w_value)
if space.exception_issubclass_w(w_valuetype, w_type):
@@ -204,18 +204,12 @@
else:
# raise Type, X: assume X is the constructor argument
w_value = space.call_function(w_type, w_value)
- w_type = space.exception_getclass(w_value)
+ w_type = self._exception_getclass(space, w_value)
else:
# the only case left here is (inst, None), from a 'raise inst'.
w_inst = w_type
- w_instclass = space.exception_getclass(w_inst)
- if not space.exception_is_valid_class_w(w_instclass):
- instclassname = w_instclass.getname(space)
- msg = ("exceptions must be old-style classes or derived "
- "from BaseException, not %s")
- raise operationerrfmt(space.w_TypeError, msg, instclassname)
-
+ w_instclass = self._exception_getclass(space, w_inst)
if not space.is_w(w_value, space.w_None):
raise OperationError(space.w_TypeError,
space.wrap("instance exception may not "
@@ -226,6 +220,15 @@
self.w_type = w_type
self._w_value = w_value
+ def _exception_getclass(self, space, w_inst):
+ w_type = space.exception_getclass(w_inst)
+ if not space.exception_is_valid_class_w(w_type):
+ typename = w_type.getname(space)
+ msg = ("exceptions must be old-style classes or derived "
+ "from BaseException, not %s")
+ raise operationerrfmt(space.w_TypeError, msg, typename)
+ return w_type
+
def write_unraisable(self, space, where, w_object=None):
if w_object is None:
objrepr = ''
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -484,44 +484,31 @@
def __init__(self, space):
AsyncAction.__init__(self, space)
- self.dying_objects_w = []
- self.weakrefs_w = []
+ self.dying_objects = []
self.finalizers_lock_count = 0
- def register_dying_object(self, w_obj):
- self.dying_objects_w.append(w_obj)
- self.fire()
-
- def register_weakref_callback(self, w_ref):
- self.weakrefs_w.append(w_ref)
+ def register_callback(self, w_obj, callback, descrname):
+ self.dying_objects.append((w_obj, callback, descrname))
self.fire()
def perform(self, executioncontext, frame):
if self.finalizers_lock_count > 0:
return
- # Each call to perform() first grabs the self.dying_objects_w
+ # Each call to perform() first grabs the self.dying_objects
# and replaces it with an empty list. We do this to try to
# avoid too deep recursions of the kind of __del__ being called
# while in the middle of another __del__ call.
- pending_w = self.dying_objects_w
- self.dying_objects_w = []
+ pending = self.dying_objects
+ self.dying_objects = []
space = self.space
- for i in range(len(pending_w)):
- w_obj = pending_w[i]
- pending_w[i] = None
+ for i in range(len(pending)):
+ w_obj, callback, descrname = pending[i]
+ pending[i] = (None, None, None)
try:
- space.userdel(w_obj)
+ callback(w_obj)
except OperationError, e:
- e.write_unraisable(space, 'method __del__ of ', w_obj)
+ e.write_unraisable(space, descrname, w_obj)
e.clear(space) # break up reference cycles
- # finally, this calls the interp-level destructor for the
- # cases where there is both an app-level and a built-in __del__.
- w_obj._call_builtin_destructor()
- pending_w = self.weakrefs_w
- self.weakrefs_w = []
- for i in range(len(pending_w)):
- w_ref = pending_w[i]
- w_ref.activate_callback()
class FrameTraceAction(AsyncAction):
"""An action that calls the local trace functions (w_f_trace)."""
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -31,7 +31,8 @@
_immutable_fields_ = ['code?',
'w_func_globals?',
'closure?',
- 'defs_w?[*]']
+ 'defs_w?[*]',
+ 'name?']
def __init__(self, space, code, w_globals=None, defs_w=[], closure=None,
forcename=None):
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -140,6 +140,9 @@
def visit_c_nonnegint(self, el, app_sig):
self.checked_space_method(el, app_sig)
+ def visit_truncatedint(self, el, app_sig):
+ self.checked_space_method(el, app_sig)
+
def visit__Wrappable(self, el, app_sig):
name = el.__name__
argname = self.orig_arg()
@@ -257,6 +260,9 @@
def visit_c_nonnegint(self, typ):
self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),))
+ def visit_truncatedint(self, typ):
+ self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),))
+
def _make_unwrap_activation_class(self, unwrap_spec, cache={}):
try:
key = tuple(unwrap_spec)
@@ -387,6 +393,9 @@
def visit_c_nonnegint(self, typ):
self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),))
+ def visit_truncatedint(self, typ):
+ self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),))
+
def make_fastfunc(unwrap_spec, func):
unwrap_info = UnwrapSpec_FastFunc_Unwrap()
unwrap_info.apply_over(unwrap_spec)
@@ -396,11 +405,14 @@
fastfunc = func
else:
# try to avoid excessive bloat
- if func.__module__ == 'pypy.interpreter.astcompiler.ast':
+ mod = func.__module__
+ if mod is None:
+ mod = ""
+ if mod == 'pypy.interpreter.astcompiler.ast':
raise FastFuncNotSupported
- if (not func.__module__.startswith('pypy.module.__builtin__') and
- not func.__module__.startswith('pypy.module.sys') and
- not func.__module__.startswith('pypy.module.math')):
+ if (not mod.startswith('pypy.module.__builtin__') and
+ not mod.startswith('pypy.module.sys') and
+ not mod.startswith('pypy.module.math')):
if not func.__name__.startswith('descr'):
raise FastFuncNotSupported
d = {}
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -114,6 +114,7 @@
def descr_close(self):
"""x.close(arg) -> raise GeneratorExit inside generator."""
+ assert isinstance(self, GeneratorIterator)
space = self.space
try:
w_retval = self.throw(space.w_GeneratorExit, space.w_None,
@@ -141,22 +142,16 @@
code_name = self.pycode.co_name
return space.wrap(code_name)
- def descr__del__(self):
- """
- applevel __del__, which is called at a safe point after the
- interp-level __del__ enqueued the object for destruction
- """
- self.descr_close()
-
def __del__(self):
# Only bother enqueuing self to raise an exception if the frame is
# still not finished and finally or except blocks are present.
- must_call_close = False
+ self.clear_all_weakrefs()
if self.frame is not None:
block = self.frame.lastblock
while block is not None:
if not isinstance(block, LoopBlock):
- must_call_close = True
+ self.enqueue_for_destruction(self.space,
+ GeneratorIterator.descr_close,
+ "interrupting generator of ")
break
block = block.previous
- self._enqueue_for_destruction(self.space, must_call_close)
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -9,6 +9,8 @@
class Module(Wrappable):
"""A module."""
+ _immutable_fields_ = ["w_dict?"]
+
_frozen = False
def __init__(self, space, w_name, w_dict=None, add_package=True):
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -119,7 +119,10 @@
raise OperationError(self.space.w_TypeError, self.space.wrap(
"invalid node type"))
- future_pos = misc.parse_future(node)
+ fut = misc.parse_future(node, self.future_flags.compiler_features)
+ f_flags, f_lineno, f_col = fut
+ future_pos = f_lineno, f_col
+ flags |= f_flags
info = pyparse.CompileInfo(filename, mode, flags, future_pos)
return self._compile_ast(node, info)
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -905,16 +905,15 @@
def SETUP_WITH(self, offsettoend, next_instr):
w_manager = self.peekvalue()
+ w_enter = self.space.lookup(w_manager, "__enter__")
w_descr = self.space.lookup(w_manager, "__exit__")
- if w_descr is None:
- raise OperationError(self.space.w_AttributeError,
- self.space.wrap("__exit__"))
+ if w_enter is None or w_descr is None:
+ typename = self.space.type(w_manager).getname(self.space)
+ raise operationerrfmt(self.space.w_AttributeError,
+ "'%s' object is not a context manager"
+ " (no __enter__/__exit__ method)", typename)
w_exit = self.space.get(w_descr, w_manager)
self.settopvalue(w_exit)
- w_enter = self.space.lookup(w_manager, "__enter__")
- if w_enter is None:
- raise OperationError(self.space.w_AttributeError,
- self.space.wrap("__enter__"))
w_result = self.space.get_and_call_function(w_enter, w_manager)
block = WithBlock(self, next_instr + offsettoend)
self.append_block(block)
diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py
--- a/pypy/interpreter/test/test_raise.py
+++ b/pypy/interpreter/test/test_raise.py
@@ -274,3 +274,9 @@
pass
except A:
pass
+
+ def test_new_returns_bad_instance(self):
+ class MyException(Exception):
+ def __new__(cls, *args):
+ return object()
+ raises(TypeError, "raise MyException")
diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -1,3 +1,4 @@
+import gc
from pypy.interpreter import typedef
from pypy.tool.udir import udir
from pypy.interpreter.baseobjspace import Wrappable
@@ -180,6 +181,85 @@
assert err.value.message == "'some_type' objects are unhashable"
""")
+ def test_destructor(self):
+ space = self.space
+ class W_Level1(Wrappable):
+ def __init__(self, space1):
+ assert space1 is space
+ def __del__(self):
+ space.call_method(w_seen, 'append', space.wrap(1))
+ class W_Level2(Wrappable):
+ def __init__(self, space1):
+ assert space1 is space
+ def __del__(self):
+ self.enqueue_for_destruction(space, W_Level2.destructormeth,
+ 'FOO ')
+ def destructormeth(self):
+ space.call_method(w_seen, 'append', space.wrap(2))
+ W_Level1.typedef = typedef.TypeDef(
+ 'level1',
+ __new__ = typedef.generic_new_descr(W_Level1))
+ W_Level2.typedef = typedef.TypeDef(
+ 'level2',
+ __new__ = typedef.generic_new_descr(W_Level2))
+ #
+ w_seen = space.newlist([])
+ W_Level1(space)
+ gc.collect(); gc.collect()
+ assert space.unwrap(w_seen) == [1]
+ #
+ w_seen = space.newlist([])
+ W_Level2(space)
+ gc.collect(); gc.collect()
+ assert space.str_w(space.repr(w_seen)) == "[]" # not called yet
+ ec = space.getexecutioncontext()
+ self.space.user_del_action.perform(ec, None)
+ assert space.unwrap(w_seen) == [2]
+ #
+ w_seen = space.newlist([])
+ self.space.appexec([self.space.gettypeobject(W_Level1.typedef)],
+ """(level1):
+ class A3(level1):
+ pass
+ A3()
+ """)
+ gc.collect(); gc.collect()
+ assert space.unwrap(w_seen) == [1]
+ #
+ w_seen = space.newlist([])
+ self.space.appexec([self.space.gettypeobject(W_Level1.typedef),
+ w_seen],
+ """(level1, seen):
+ class A4(level1):
+ def __del__(self):
+ seen.append(4)
+ A4()
+ """)
+ gc.collect(); gc.collect()
+ assert space.unwrap(w_seen) == [4, 1]
+ #
+ w_seen = space.newlist([])
+ self.space.appexec([self.space.gettypeobject(W_Level2.typedef)],
+ """(level2):
+ class A5(level2):
+ pass
+ A5()
+ """)
+ gc.collect(); gc.collect()
+ assert space.unwrap(w_seen) == [2]
+ #
+ w_seen = space.newlist([])
+ self.space.appexec([self.space.gettypeobject(W_Level2.typedef),
+ w_seen],
+ """(level2, seen):
+ class A6(level2):
+ def __del__(self):
+ seen.append(6)
+ A6()
+ """)
+ gc.collect(); gc.collect()
+ assert space.unwrap(w_seen) == [6, 2]
+
class AppTestTypeDef:
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -23,7 +23,7 @@
self.hasdict |= __base.hasdict
self.weakrefable |= __base.weakrefable
self.rawdict = {}
- self.acceptable_as_base_class = True
+ self.acceptable_as_base_class = '__new__' in rawdict
self.applevel_subclasses_base = None
# xxx used by faking
self.fakedcpytype = None
@@ -228,21 +228,26 @@
return self._lifeline_
def setweakref(self, space, weakreflifeline):
self._lifeline_ = weakreflifeline
+ def delweakref(self):
+ self._lifeline_ = None
add(Proto)
if "del" in features:
+ parent_destructor = getattr(supercls, '__del__', None)
+ def call_parent_del(self):
+ assert isinstance(self, subcls)
+ parent_destructor(self)
+ def call_applevel_del(self):
+ assert isinstance(self, subcls)
+ self.space.userdel(self)
class Proto(object):
def __del__(self):
- self._enqueue_for_destruction(self.space)
- # if the base class needs its own interp-level __del__,
- # we override the _call_builtin_destructor() method to invoke it
- # after the app-level destructor.
- parent_destructor = getattr(supercls, '__del__', None)
- if parent_destructor is not None:
- def _call_builtin_destructor(self):
- parent_destructor(self)
- Proto._call_builtin_destructor = _call_builtin_destructor
-
+ self.clear_all_weakrefs()
+ self.enqueue_for_destruction(self.space, call_applevel_del,
+ 'method __del__ of ')
+ if parent_destructor is not None:
+ self.enqueue_for_destruction(self.space, call_parent_del,
+ 'internal destructor of ')
add(Proto)
if "slots" in features:
@@ -630,9 +635,12 @@
return self._lifeline_
def setweakref(self, space, weakreflifeline):
self._lifeline_ = weakreflifeline
+ def delweakref(self):
+ self._lifeline_ = None
cls._lifeline_ = None
cls.getweakref = getweakref
cls.setweakref = setweakref
+ cls.delweakref = delweakref
return weakref_descr
@@ -858,8 +866,6 @@
descrmismatch='close'),
__iter__ = interp2app(GeneratorIterator.descr__iter__,
descrmismatch='__iter__'),
- __del__ = interp2app(GeneratorIterator.descr__del__,
- descrmismatch='__del__'),
gi_running = interp_attrproperty('running', cls=GeneratorIterator),
gi_frame = GetSetProperty(GeneratorIterator.descr_gi_frame),
gi_code = GetSetProperty(GeneratorIterator.descr_gi_code),
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -453,21 +453,33 @@
class WriteBarrierDescr(AbstractDescr):
def __init__(self, gc_ll_descr):
+ GCClass = gc_ll_descr.GCClass
self.llop1 = gc_ll_descr.llop1
self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR
- self.fielddescr_tid = get_field_descr(gc_ll_descr,
- gc_ll_descr.GCClass.HDR, 'tid')
- self.jit_wb_if_flag = gc_ll_descr.GCClass.JIT_WB_IF_FLAG
- # if convenient for the backend, we also compute the info about
+ self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid')
+ #
+ self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
+ self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = (
+ self.extract_flag_byte(self.jit_wb_if_flag))
+ #
+ if hasattr(GCClass, 'JIT_WB_CARDS_SET'):
+ self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET
+ self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT
+ self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = (
+ self.extract_flag_byte(self.jit_wb_cards_set))
+ else:
+ self.jit_wb_cards_set = 0
+
+ def extract_flag_byte(self, flag_word):
+ # if convenient for the backend, we compute the info about
# the flag as (byte-offset, single-byte-flag).
import struct
- value = struct.pack("l", self.jit_wb_if_flag)
+ value = struct.pack("l", flag_word)
assert value.count('\x00') == len(value) - 1 # only one byte is != 0
i = 0
while value[i] == '\x00': i += 1
- self.jit_wb_if_flag_byteofs = i
- self.jit_wb_if_flag_singlebyte = struct.unpack('b', value[i])[0]
+ return (i, struct.unpack('b', value[i])[0])
def get_write_barrier_fn(self, cpu):
llop1 = self.llop1
diff --git a/pypy/jit/backend/llvm/llvm_rffi.py b/pypy/jit/backend/llvm/llvm_rffi.py
--- a/pypy/jit/backend/llvm/llvm_rffi.py
+++ b/pypy/jit/backend/llvm/llvm_rffi.py
@@ -3,7 +3,7 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo, log
-if sys.platform != 'linux2':
+if not sys.platform.startswith('linux'):
py.test.skip("Linux only for now")
# ____________________________________________________________
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1707,6 +1707,7 @@
jit_wb_if_flag = 4096
jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
jit_wb_if_flag_singlebyte = 0x10
+ jit_wb_cards_set = 0
def get_write_barrier_from_array_fn(self, cpu):
return funcbox.getint()
#
@@ -1728,6 +1729,72 @@
else:
assert record == []
+ def test_cond_call_gc_wb_array_card_marking_fast_path(self):
+ def func_void(a, b, c):
+ record.append((a, b, c))
+ record = []
+ #
+ S = lltype.Struct('S', ('tid', lltype.Signed))
+ S_WITH_CARDS = lltype.Struct('S_WITH_CARDS',
+ ('card0', lltype.Char),
+ ('card1', lltype.Char),
+ ('card2', lltype.Char),
+ ('card3', lltype.Char),
+ ('card4', lltype.Char),
+ ('card5', lltype.Char),
+ ('card6', lltype.Char),
+ ('card7', lltype.Char),
+ ('data', S))
+ FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)],
+ lltype.Void)
+ func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
+ funcbox = self.get_funcbox(self.cpu, func_ptr)
+ class WriteBarrierDescr(AbstractDescr):
+ jit_wb_if_flag = 4096
+ jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
+ jit_wb_if_flag_singlebyte = 0x10
+ jit_wb_cards_set = 8192
+ jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20')
+ jit_wb_cards_set_singlebyte = 0x20
+ jit_wb_card_page_shift = 7
+ def get_write_barrier_from_array_fn(self, cpu):
+ return funcbox.getint()
+ #
+ for BoxIndexCls in [BoxInt, ConstInt]:
+ for cond in [False, True]:
+ print
+ print '_'*79
+ print 'BoxIndexCls =', BoxIndexCls
+ print 'JIT_WB_CARDS_SET =', cond
+ print
+ value = random.randrange(-sys.maxint, sys.maxint)
+ value |= 4096
+ if cond:
+ value |= 8192
+ else:
+ value &= ~8192
+ s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True)
+ s.data.tid = value
+ sgcref = rffi.cast(llmemory.GCREF, s.data)
+ del record[:]
+ box_index = BoxIndexCls((9<<7) + 17)
+ self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
+ [BoxPtr(sgcref), box_index, BoxPtr(sgcref)],
+ 'void', descr=WriteBarrierDescr())
+ if cond:
+ assert record == []
+ assert s.card6 == '\x02'
+ else:
+ assert record == [(s.data, (9<<7) + 17, s.data)]
+ assert s.card6 == '\x00'
+ assert s.card0 == '\x00'
+ assert s.card1 == '\x00'
+ assert s.card2 == '\x00'
+ assert s.card3 == '\x00'
+ assert s.card4 == '\x00'
+ assert s.card5 == '\x00'
+ assert s.card7 == '\x00'
+
def test_force_operations_returning_void(self):
values = []
def maybe_force(token, flag):
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -416,10 +416,13 @@
fullsize = self.mc.get_relative_pos()
#
rawstart = self.materialize_loop(looptoken)
- debug_print("Loop #%d (%s) has address %x to %x" % (
+ debug_start("jit-backend-addr")
+ debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % (
looptoken.number, loopname,
rawstart + self.looppos,
- rawstart + directbootstrappos))
+ rawstart + directbootstrappos,
+ rawstart))
+ debug_stop("jit-backend-addr")
self._patch_stackadjust(rawstart + stackadjustpos,
frame_depth + param_depth)
self.patch_pending_failure_recoveries(rawstart)
@@ -478,9 +481,10 @@
fullsize = self.mc.get_relative_pos()
#
rawstart = self.materialize_loop(original_loop_token)
-
- debug_print("Bridge out of guard %d has address %x to %x" %
+ debug_start("jit-backend-addr")
+ debug_print("bridge out of Guard %d has address %x to %x" %
(descr_number, rawstart, rawstart + codeendpos))
+ debug_stop("jit-backend-addr")
self._patch_stackadjust(rawstart + stackadjustpos,
frame_depth + param_depth)
self.patch_pending_failure_recoveries(rawstart)
@@ -2242,10 +2246,12 @@
if opnum == rop.COND_CALL_GC_WB:
N = 2
func = descr.get_write_barrier_fn(self.cpu)
+ card_marking = False
elif opnum == rop.COND_CALL_GC_WB_ARRAY:
N = 3
func = descr.get_write_barrier_from_array_fn(self.cpu)
assert func != 0
+ card_marking = descr.jit_wb_cards_set != 0
else:
raise AssertionError(opnum)
#
@@ -2254,6 +2260,18 @@
imm(descr.jit_wb_if_flag_singlebyte))
self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later
jz_location = self.mc.get_relative_pos()
+
+ # for cond_call_gc_wb_array, also add another fast path:
+ # if GCFLAG_CARDS_SET, then we can just set one bit and be done
+ if card_marking:
+ self.mc.TEST8(addr_add_const(loc_base,
+ descr.jit_wb_cards_set_byteofs),
+ imm(descr.jit_wb_cards_set_singlebyte))
+ self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later
+ jnz_location = self.mc.get_relative_pos()
+ else:
+ jnz_location = 0
+
# the following is supposed to be the slow path, so whenever possible
# we choose the most compact encoding over the most efficient one.
if IS_X86_32:
@@ -2293,6 +2311,43 @@
loc = arglocs[i]
assert isinstance(loc, RegLoc)
self.mc.POP_r(loc.value)
+
+ # if GCFLAG_CARDS_SET, then we can do the whole thing that would
+ # be done in the CALL above with just four instructions, so here
+ # is an inline copy of them
+ if card_marking:
+ self.mc.JMP_l8(0) # jump to the exit, patched later
+ jmp_location = self.mc.get_relative_pos()
+ # patch the JNZ above
+ offset = self.mc.get_relative_pos() - jnz_location
+ assert 0 < offset <= 127
+ self.mc.overwrite(jnz_location-1, chr(offset))
+ #
+ loc_index = arglocs[1]
+ if isinstance(loc_index, RegLoc):
+ # choose a scratch register
+ tmp1 = loc_index
+ self.mc.PUSH_r(tmp1.value)
+ # SHR tmp, card_page_shift
+ self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift)
+ # XOR tmp, -8
+ self.mc.XOR_ri(tmp1.value, -8)
+ # BTS [loc_base], tmp
+ self.mc.BTS(addr_add_const(loc_base, 0), tmp1)
+ # done
+ self.mc.POP_r(tmp1.value)
+ elif isinstance(loc_index, ImmedLoc):
+ byte_index = loc_index.value >> descr.jit_wb_card_page_shift
+ byte_ofs = ~(byte_index >> 3)
+ byte_val = 1 << (byte_index & 7)
+ self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val))
+ else:
+ raise AssertionError("index is neither RegLoc nor ImmedLoc")
+ # patch the JMP above
+ offset = self.mc.get_relative_pos() - jmp_location
+ assert 0 < offset <= 127
+ self.mc.overwrite(jmp_location-1, chr(offset))
+ #
# patch the JZ above
offset = self.mc.get_relative_pos() - jz_location
assert 0 < offset <= 127
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -476,6 +476,7 @@
AND = _binaryop('AND')
OR = _binaryop('OR')
+ OR8 = _binaryop('OR8')
XOR = _binaryop('XOR')
NOT = _unaryop('NOT')
SHL = _binaryop('SHL')
@@ -483,6 +484,7 @@
SAR = _binaryop('SAR')
TEST = _binaryop('TEST')
TEST8 = _binaryop('TEST8')
+ BTS = _binaryop('BTS')
ADD = _binaryop('ADD')
SUB = _binaryop('SUB')
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -464,7 +464,7 @@
# ------------------------------ MOV ------------------------------
- MOV_ri = insn(rex_w, register(1), '\xB8', immediate(2, 'q'))
+ MOV_ri = insn(register(1), '\xB8', immediate(2))
MOV8_ri = insn(rex_fw, byte_register(1), '\xB0', immediate(2, 'b'))
# ------------------------------ Arithmetic ------------------------------
@@ -496,6 +496,10 @@
AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0')
OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0')
+ OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1),
+ immediate(2, 'b'))
+ OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1),
+ immediate(2, 'b'))
NEG_r = insn(rex_w, '\xF7', register(1), '\xD8')
@@ -565,6 +569,9 @@
TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b'))
TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0')
+ BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1))
+ BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_, immediate(1))
+
# x87 instructions
FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1))
@@ -632,16 +639,20 @@
CQO = insn(rex_w, '\x99')
- # MOV_ri from the parent class is not wrong, but here is a better encoding
- # for the common case where the immediate fits in 32 bits
+ # Three different encodings... following what gcc does. From the
+ # shortest encoding to the longest one.
+ MOV_riu32 = insn(rex_nw, register(1), '\xB8', immediate(2, 'i'))
MOV_ri32 = insn(rex_w, '\xC7', register(1), '\xC0', immediate(2, 'i'))
- MOV_ri64 = AbstractX86CodeBuilder.MOV_ri
+ MOV_ri64 = insn(rex_w, register(1), '\xB8', immediate(2, 'q'))
def MOV_ri(self, reg, immed):
- if fits_in_32bits(immed):
+ if 0 <= immed <= 4294967295:
+ immed = intmask(rffi.cast(rffi.INT, immed))
+ self.MOV_riu32(reg, immed)
+ elif fits_in_32bits(immed): # for negative values that fit in 32 bit
self.MOV_ri32(reg, immed)
else:
- AbstractX86CodeBuilder.MOV_ri(self, reg, immed)
+ self.MOV_ri64(reg, immed)
def define_modrm_modes(insnname_template, before_modrm, after_modrm=[], regtype='GPR'):
def add_insn(code, *modrm):
diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py
--- a/pypy/jit/backend/x86/test/test_regloc.py
+++ b/pypy/jit/backend/x86/test/test_regloc.py
@@ -24,9 +24,14 @@
assert_encodes_as(cb64, "MOV16", (r8, ebx), '\x66\x41\x89\xD8') # 11 011 000
assert_encodes_as(cb64, "MOV16", (ebx, r8), '\x66\x44\x89\xC3') # 11 000 011
assert_encodes_as(cb64, "MOV16", (ecx, ebx), '\x66\x40\x89\xD9')
- # XXX: What we are testing for here is actually not the most compact
- # encoding.
- assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\x40\xC7\xC1\x39\x30')
+ assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(12345)), '\x66\xB9\x39\x30')
+ # for the next case we don't pick the most efficient encoding, but well
+ expected = '\x66\x40\xC7\xC1\xC7\xCF' # could be '\x66\xB9\xC7\xCF'
+ assert_encodes_as(cb64, "MOV16", (ecx, ImmedLoc(-12345)), expected)
+ assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(12345)), '\x66\x41\xB9\x39\x30')
+ # for the next case we don't pick the most efficient encoding, but well
+ expected = '\x66\x41\xC7\xC1\xC7\xCF' # could be '\x66\x41\xB9\xC7\xCF'
+ assert_encodes_as(cb64, "MOV16", (r9, ImmedLoc(-12345)), expected)
assert_encodes_as(cb64, "MOV16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\xC7\x45\x00\x39\x30')
def test_cmp_16():
@@ -44,7 +49,7 @@
def test_relocation():
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.jit.backend.x86 import codebuf
- for target in [0x01020304, 0x0102030405060708]:
+ for target in [0x01020304, -0x05060708, 0x0102030405060708]:
if target > sys.maxint:
continue
mc = codebuf.MachineCodeBlockWrapper()
@@ -58,10 +63,15 @@
expected = "\xE8" + struct.pack('<i', target - (rawstart + 5))
elif IS_X86_64:
assert mc.relocations == []
- if target <= 0x7fffffff:
+ if 0 <= target <= 0xffffffff:
+ assert length == 9
+ expected = (
+ "\x41\xBB\x04\x03\x02\x01" # MOV %r11, target
+ "\x41\xFF\xD3") # CALL *%r11
+ elif -0x80000000 <= target < 0:
assert length == 10
expected = (
- "\x49\xC7\xC3\x04\x03\x02\x01" # MOV %r11, target
+ "\x49\xC7\xC3\xF8\xF8\xF9\xFA" # MOV %r11, target
"\x41\xFF\xD3") # CALL *%r11
else:
assert length == 13
diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py
--- a/pypy/jit/backend/x86/test/test_rx86.py
+++ b/pypy/jit/backend/x86/test/test_rx86.py
@@ -198,9 +198,19 @@
def test_mov_ri_64():
s = CodeBuilder64()
s.MOV_ri(ecx, -2)
+ s.MOV_ri(r15, -3)
+ s.MOV_ri(ebx, -0x80000003)
+ s.MOV_ri(r13, -0x80000002)
+ s.MOV_ri(ecx, 42)
s.MOV_ri(r12, 0x80000042)
+ s.MOV_ri(r12, 0x100000007)
assert s.getvalue() == ('\x48\xC7\xC1\xFE\xFF\xFF\xFF' +
- '\x49\xBC\x42\x00\x00\x80\x00\x00\x00\x00')
+ '\x49\xC7\xC7\xFD\xFF\xFF\xFF' +
+ '\x48\xBB\xFD\xFF\xFF\x7F\xFF\xFF\xFF\xFF' +
+ '\x49\xBD\xFE\xFF\xFF\x7F\xFF\xFF\xFF\xFF' +
+ '\xB9\x2A\x00\x00\x00' +
+ '\x41\xBC\x42\x00\x00\x80' +
+ '\x49\xBC\x07\x00\x00\x00\x01\x00\x00\x00')
def test_mov_rm_64():
s = CodeBuilder64()
diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
--- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
+++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
@@ -212,6 +212,17 @@
for mode, v in zip(argmodes, args):
ops.append(assembler_operand[mode](v))
ops.reverse()
+ #
+ if (instrname.lower() == 'mov' and suffix == 'q' and
+ ops[0].startswith('$') and 0 <= int(ops[0][1:]) <= 4294967295
+ and ops[1].startswith('%r')):
+ # movq $xxx, %rax => movl $xxx, %eax
+ suffix = 'l'
+ if ops[1][2:].isdigit():
+ ops[1] += 'd'
+ else:
+ ops[1] = '%e' + ops[1][2:]
+ #
op = '\t%s%s %s%s' % (instrname.lower(), suffix,
', '.join(ops), following)
g.write('%s\n' % op)
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -524,6 +524,76 @@
def test_compile_framework_8(self):
self.run('compile_framework_8')
+ def define_compile_framework_9(cls):
+ # Like compile_framework_8, but with variable indexes and large
+ # arrays, testing the card_marking case
+ def before(n, x):
+ return n, x, None, None, None, None, None, None, None, None, [X(123)], None
+ def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
+ if n < 1900:
+ check(l[0].x == 123)
+ num = 512 + (n & 7)
+ l = [None] * num
+ l[0] = X(123)
+ l[1] = X(n)
+ l[2] = X(n+10)
+ l[3] = X(n+20)
+ l[4] = X(n+30)
+ l[5] = X(n+40)
+ l[6] = X(n+50)
+ l[7] = X(n+60)
+ l[num-8] = X(n+70)
+ l[num-9] = X(n+80)
+ l[num-10] = X(n+90)
+ l[num-11] = X(n+100)
+ l[-12] = X(n+110)
+ l[-13] = X(n+120)
+ l[-14] = X(n+130)
+ l[-15] = X(n+140)
+ if n < 1800:
+ num = 512 + (n & 7)
+ check(len(l) == num)
+ check(l[0].x == 123)
+ check(l[1].x == n)
+ check(l[2].x == n+10)
+ check(l[3].x == n+20)
+ check(l[4].x == n+30)
+ check(l[5].x == n+40)
+ check(l[6].x == n+50)
+ check(l[7].x == n+60)
+ check(l[num-8].x == n+70)
+ check(l[num-9].x == n+80)
+ check(l[num-10].x == n+90)
+ check(l[num-11].x == n+100)
+ check(l[-12].x == n+110)
+ check(l[-13].x == n+120)
+ check(l[-14].x == n+130)
+ check(l[-15].x == n+140)
+ n -= x.foo
+ return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
+ def after(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
+ check(len(l) >= 512)
+ check(l[0].x == 123)
+ check(l[1].x == 2)
+ check(l[2].x == 12)
+ check(l[3].x == 22)
+ check(l[4].x == 32)
+ check(l[5].x == 42)
+ check(l[6].x == 52)
+ check(l[7].x == 62)
+ check(l[-8].x == 72)
+ check(l[-9].x == 82)
+ check(l[-10].x == 92)
+ check(l[-11].x == 102)
+ check(l[-12].x == 112)
+ check(l[-13].x == 122)
+ check(l[-14].x == 132)
+ check(l[-15].x == 142)
+ return before, f, after
+
+ def test_compile_framework_9(self):
+ self.run('compile_framework_9')
+
def define_compile_framework_external_exception_handling(cls):
def before(n, x):
x = X(0)
diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py
--- a/pypy/jit/codewriter/call.py
+++ b/pypy/jit/codewriter/call.py
@@ -5,10 +5,9 @@
from pypy.jit.codewriter import support
from pypy.jit.codewriter.jitcode import JitCode
-from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer
-from pypy.jit.codewriter.effectinfo import QuasiImmutAnalyzer
-from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
-from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection
+from pypy.jit.codewriter.effectinfo import (VirtualizableAnalyzer,
+ QuasiImmutAnalyzer, CanReleaseGILAnalyzer, effectinfo_from_writeanalyze,
+ EffectInfo, CallInfoCollection)
from pypy.translator.simplify import get_funcobj, get_functype
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.translator.backendopt.canraise import RaiseAnalyzer
@@ -32,6 +31,7 @@
self.readwrite_analyzer = ReadWriteAnalyzer(translator)
self.virtualizable_analyzer = VirtualizableAnalyzer(translator)
self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator)
+ self.canreleasegil_analyzer = CanReleaseGILAnalyzer(translator)
#
for index, jd in enumerate(jitdrivers_sd):
jd.index = index
@@ -219,7 +219,9 @@
assert not NON_VOID_ARGS, ("arguments not supported for "
"loop-invariant function!")
# build the extraeffect
- can_invalidate = self.quasiimmut_analyzer.analyze(op)
+ can_release_gil = self.canreleasegil_analyzer.analyze(op)
+ # can_release_gil implies can_invalidate
+ can_invalidate = can_release_gil or self.quasiimmut_analyzer.analyze(op)
if extraeffect is None:
if self.virtualizable_analyzer.analyze(op):
extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
@@ -235,7 +237,7 @@
#
effectinfo = effectinfo_from_writeanalyze(
self.readwrite_analyzer.analyze(op), self.cpu, extraeffect,
- oopspecindex, can_invalidate)
+ oopspecindex, can_invalidate, can_release_gil)
#
if oopspecindex != EffectInfo.OS_NONE:
assert effectinfo is not None
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -79,13 +79,15 @@
write_descrs_fields, write_descrs_arrays,
extraeffect=EF_CAN_RAISE,
oopspecindex=OS_NONE,
- can_invalidate=False):
+ can_invalidate=False, can_release_gil=False):
key = (frozenset(readonly_descrs_fields),
frozenset(readonly_descrs_arrays),
frozenset(write_descrs_fields),
frozenset(write_descrs_arrays),
extraeffect,
- oopspecindex)
+ oopspecindex,
+ can_invalidate,
+ can_release_gil)
if key in cls._cache:
return cls._cache[key]
result = object.__new__(cls)
@@ -100,6 +102,7 @@
result.write_descrs_arrays = write_descrs_arrays
result.extraeffect = extraeffect
result.can_invalidate = can_invalidate
+ result.can_release_gil = can_release_gil
result.oopspecindex = oopspecindex
cls._cache[key] = result
return result
@@ -111,12 +114,13 @@
return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
def has_random_effects(self):
- return self.oopspecindex == self.OS_LIBFFI_CALL
+ return self.oopspecindex == self.OS_LIBFFI_CALL or self.can_release_gil
def effectinfo_from_writeanalyze(effects, cpu,
extraeffect=EffectInfo.EF_CAN_RAISE,
oopspecindex=EffectInfo.OS_NONE,
- can_invalidate=False):
+ can_invalidate=False,
+ can_release_gil=False):
from pypy.translator.backendopt.writeanalyze import top_set
if effects is top_set:
return None
@@ -158,7 +162,8 @@
write_descrs_arrays,
extraeffect,
oopspecindex,
- can_invalidate)
+ can_invalidate,
+ can_release_gil)
def consider_struct(TYPE, fieldname):
if fieldType(TYPE, fieldname) is lltype.Void:
@@ -194,6 +199,16 @@
def analyze_simple_operation(self, op, graphinfo):
return op.opname == 'jit_force_quasi_immutable'
+class CanReleaseGILAnalyzer(BoolGraphAnalyzer):
+ def analyze_direct_call(self, graph, seen=None):
+ releases_gil = False
+ if hasattr(graph, "func") and hasattr(graph.func, "_ptr"):
+ releases_gil = graph.func._ptr._obj.releases_gil
+ return releases_gil or super(CanReleaseGILAnalyzer, self).analyze_direct_call(graph, seen)
+
+ def analyze_simple_operation(self, op, graphinfo):
+ return False
+
# ____________________________________________________________
class CallInfoCollection(object):
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -765,13 +765,65 @@
raise NotImplementedError("cast_ptr_to_int")
def rewrite_op_force_cast(self, op):
- from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof
+ assert not self._is_gc(op.args[0])
+ fromll = longlong.is_longlong(op.args[0].concretetype)
+ toll = longlong.is_longlong(op.result.concretetype)
+ if fromll and toll:
+ return
+ if fromll:
+ args = op.args
+ opname = 'truncate_longlong_to_int'
+ RESULT = lltype.Signed
+ v = varoftype(RESULT)
+ op1 = SpaceOperation(opname, args, v)
+ op2 = self.rewrite_operation(op1)
+ oplist = self.force_cast_without_longlong(op2.result, op.result)
+ if oplist:
+ return [op2] + oplist
+ #
+ # force a renaming to put the correct result in place, even though
+ # it might be slightly mistyped (e.g. Signed versus Unsigned)
+ assert op2.result is v
+ op2.result = op.result
+ return op2
+ elif toll:
+ from pypy.rpython.lltypesystem import rffi
+ size, unsigned = rffi.size_and_sign(op.args[0].concretetype)
+ if unsigned:
+ INTERMEDIATE = lltype.Unsigned
+ else:
+ INTERMEDIATE = lltype.Signed
+ v = varoftype(INTERMEDIATE)
+ oplist = self.force_cast_without_longlong(op.args[0], v)
+ if not oplist:
+ v = op.args[0]
+ oplist = []
+ if unsigned:
+ opname = 'cast_uint_to_longlong'
+ else:
+ opname = 'cast_int_to_longlong'
+ op1 = SpaceOperation(opname, [v], op.result)
+ op2 = self.rewrite_operation(op1)
+ return oplist + [op2]
+ else:
+ return self.force_cast_without_longlong(op.args[0], op.result)
+
+ def force_cast_without_longlong(self, v_arg, v_result):
+ from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof, FLOAT
from pypy.rlib.rarithmetic import intmask
- assert not self._is_gc(op.args[0])
- size2, unsigned2 = size_and_sign(op.result.concretetype)
- if size2 >= sizeof(lltype.Signed):
+ #
+ if (v_result.concretetype in (FLOAT, lltype.Float) or
+ v_arg.concretetype in (FLOAT, lltype.Float)):
+ assert (v_result.concretetype == lltype.Float and
+ v_arg.concretetype == lltype.Float), "xxx unsupported cast"
+ return
+ #
+ size2, unsigned2 = size_and_sign(v_result.concretetype)
+ assert size2 <= sizeof(lltype.Signed)
+ if size2 == sizeof(lltype.Signed):
return # the target type is LONG or ULONG
- size1, unsigned1 = size_and_sign(op.args[0].concretetype)
+ size1, unsigned1 = size_and_sign(v_arg.concretetype)
+ assert size1 <= sizeof(lltype.Signed)
#
def bounds(size, unsigned):
if unsigned:
@@ -784,22 +836,28 @@
return # the target type includes the source range
#
result = []
- v1 = op.args[0]
if min2:
c_min2 = Constant(min2, lltype.Signed)
- v2 = Variable(); v2.concretetype = lltype.Signed
- result.append(SpaceOperation('int_sub', [v1, c_min2], v2))
+ v2 = varoftype(lltype.Signed)
+ result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
else:
- v2 = v1
+ v2 = v_arg
c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed)
- v3 = Variable(); v3.concretetype = lltype.Signed
+ v3 = varoftype(lltype.Signed)
result.append(SpaceOperation('int_and', [v2, c_mask], v3))
if min2:
- result.append(SpaceOperation('int_add', [v3, c_min2], op.result))
+ result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
else:
- result[-1].result = op.result
+ result[-1].result = v_result
return result
+ def rewrite_op_direct_ptradd(self, op):
+ from pypy.rpython.lltypesystem import rffi
+ # xxx otherwise, not implemented:
+ assert op.args[0].concretetype == rffi.CCHARP
+ #
+ return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result)
+
# ----------
# Long longs, for 32-bit only. Supported operations are left unmodified,
# and unsupported ones are turned into a call to a function from
@@ -883,30 +941,7 @@
rewrite_op_ullong_is_true = rewrite_op_llong_is_true
def rewrite_op_cast_primitive(self, op):
- fromll = longlong.is_longlong(op.args[0].concretetype)
- toll = longlong.is_longlong(op.result.concretetype)
- if fromll != toll:
- args = op.args
- if fromll:
- opname = 'truncate_longlong_to_int'
- RESULT = lltype.Signed
- else:
- from pypy.rpython.lltypesystem import rffi
- if rffi.cast(op.args[0].concretetype, -1) < 0:
- opname = 'cast_int_to_longlong'
- else:
- opname = 'cast_uint_to_longlong'
- RESULT = lltype.SignedLongLong
- v = varoftype(RESULT)
- op1 = SpaceOperation(opname, args, v)
- op2 = self.rewrite_operation(op1)
- #
- # force a renaming to put the correct result in place, even though
- # it might be slightly mistyped (e.g. Signed versus Unsigned)
- assert op2.result is v
- op2.result = op.result
- #
- return op2
+ return self.rewrite_op_force_cast(op)
# ----------
# Renames, from the _old opname to the _new one.
@@ -1083,6 +1118,9 @@
return meth(op, args, *descrs)
def _get_list_nonneg_canraise_flags(self, op):
+ # XXX as far as I can see, this function will always return True
+ # because functions that are neither nonneg nor fast don't have an
+ # oopspec any more
# xxx break of abstraction:
func = get_funcobj(op.args[0].value)._callable
# base hints on the name of the ll function, which is a bit xxx-ish
@@ -1240,7 +1278,7 @@
calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
extraeffect)
if extraeffect is not None:
- assert (type(calldescr) is str # for tests
+ assert (is_test_calldescr(calldescr) # for tests
or calldescr.get_extra_info().extraeffect == extraeffect)
if isinstance(op.args[0].value, str):
pass # for tests only
@@ -1401,6 +1439,9 @@
return "using virtualizable array in illegal way in %r" % (
self.args[0],)
+def is_test_calldescr(calldescr):
+ return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False)
+
def _with_prefix(prefix):
result = {}
for name in dir(Transformer):
diff --git a/pypy/jit/codewriter/regalloc.py b/pypy/jit/codewriter/regalloc.py
--- a/pypy/jit/codewriter/regalloc.py
+++ b/pypy/jit/codewriter/regalloc.py
@@ -96,6 +96,7 @@
def _try_coalesce(self, v, w):
if isinstance(v, Variable) and getkind(v.concretetype) == self.kind:
+ assert getkind(w.concretetype) == self.kind
dg = self._depgraph
uf = self._unionfind
v0 = uf.find_rep(v)
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -185,7 +185,7 @@
return llop.int_floordiv(lltype.Signed, x, y)
def _ll_2_int_floordiv_ovf(x, y):
- if x == -sys.maxint - 1 and y == -1:
+ if x == -sys.maxint - 1 and y == -1:
raise OverflowError
return llop.int_floordiv(lltype.Signed, x, y)
@@ -222,7 +222,7 @@
return -x
else:
return x
-
+
# math support
# ------------
@@ -395,7 +395,7 @@
('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed),
('int_abs', [lltype.Signed], lltype.Signed),
('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float),
- ]
+]
class LLtypeHelpers:
diff --git a/pypy/jit/codewriter/test/test_call.py b/pypy/jit/codewriter/test/test_call.py
--- a/pypy/jit/codewriter/test/test_call.py
+++ b/pypy/jit/codewriter/test/test_call.py
@@ -1,6 +1,6 @@
import py
from pypy.objspace.flow.model import SpaceOperation, Constant, Variable
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, rffi
from pypy.translator.unsimplify import varoftype
from pypy.rlib import jit
from pypy.jit.codewriter.call import CallControl
@@ -103,7 +103,7 @@
op = SpaceOperation('direct_call', [Constant(object())],
Variable())
- assert cc.guess_call_kind(op) == 'residual'
+ assert cc.guess_call_kind(op) == 'residual'
class funcptr:
class graph:
@@ -118,7 +118,7 @@
op = SpaceOperation('direct_call', [Constant(funcptr)],
Variable())
res = cc.graphs_from(op)
- assert res == [g]
+ assert res == [g]
assert cc.guess_call_kind(op) == 'regular'
class funcptr:
@@ -126,7 +126,7 @@
op = SpaceOperation('direct_call', [Constant(funcptr)],
Variable())
res = cc.graphs_from(op)
- assert res is None
+ assert res is None
assert cc.guess_call_kind(op) == 'residual'
h = object()
@@ -142,7 +142,7 @@
Variable())
res = cc.graphs_from(op)
assert res is None
- assert cc.guess_call_kind(op) == 'residual'
+ assert cc.guess_call_kind(op) == 'residual'
# ____________________________________________________________
@@ -171,3 +171,24 @@
def test_jit_force_virtualizable_effectinfo():
py.test.skip("XXX add a test for CallControl.getcalldescr() -> EF_xxx")
+
+def test_releases_gil_analyzer():
+ from pypy.jit.backend.llgraph.runner import LLtypeCPU
+
+ T = rffi.CArrayPtr(rffi.TIME_T)
+ external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True)
+
+ @jit.dont_look_inside
+ def f():
+ return external(lltype.nullptr(T.TO))
+
+ rtyper = support.annotate(f, [])
+ jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
+ cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
+ res = cc.find_all_graphs(FakePolicy())
+
+ [f_graph] = [x for x in res if x.func is f]
+ [block, _] = list(f_graph.iterblocks())
+ [op] = block.operations
+ call_descr = cc.getcalldescr(op)
+ assert call_descr.extrainfo.can_release_gil
\ No newline at end of file
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -3,6 +3,7 @@
from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list
from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register
from pypy.jit.codewriter.format import assert_format
+from pypy.jit.codewriter import longlong
from pypy.jit.metainterp.history import AbstractDescr
from pypy.rpython.lltypesystem import lltype, rclass, rstr
from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
@@ -30,6 +31,9 @@
'float': FakeRegAlloc()}
class FakeDescr(AbstractDescr):
+ _for_tests_only = True
+ def __init__(self, oopspecindex=None):
+ self.oopspecindex = oopspecindex
def __repr__(self):
return '<Descr>'
def as_vtable_size_descr(self):
@@ -55,19 +59,24 @@
def arraydescrof(self, ARRAY):
return FakeDescr()
+class FakeCallInfoCollection:
+ def add(self, *args):
+ pass
+
class FakeCallControl:
_descr_cannot_raise = FakeDescr()
+ callinfocollection = FakeCallInfoCollection()
def guess_call_kind(self, op):
return 'residual'
- def getcalldescr(self, op):
+ def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
try:
if 'cannot_raise' in op.args[0].value._obj.graph.name:
return self._descr_cannot_raise
except AttributeError:
pass
- return FakeDescr()
+ return FakeDescr(oopspecindex)
def calldescr_canraise(self, calldescr):
- return calldescr is not self._descr_cannot_raise
+ return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None
def get_vinfo(self, VTYPEPTR):
return None
@@ -734,7 +743,9 @@
def test_force_cast(self):
from pypy.rpython.lltypesystem import rffi
-
+ # NB: we don't need to test for INT here, the logic in jtransform is
+ # general enough so that if we have the below cases it should
+ # generalize also to INT
for FROM, TO, expected in [
(rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""),
(rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
@@ -797,14 +808,44 @@
expected = [s.strip() for s in expected.splitlines()]
check_force_cast(FROM, TO, expected, 42)
check_force_cast(FROM, TO, expected, -42)
- expected.append('int_return %i' + str(len(expected)))
- expected = '\n'.join(expected)
+ returnvar = "%i" + str(len(expected))
+ expected.append('int_return ' + returnvar)
+ expectedstr = '\n'.join(expected)
#
def f(n):
return rffi.cast(TO, n)
- self.encoding_test(f, [rffi.cast(FROM, 42)], expected,
+ self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
transform=True)
+ if not longlong.is_64_bit:
+ if FROM in (rffi.LONG, rffi.ULONG):
+ if FROM == rffi.LONG:
+ FROM = rffi.LONGLONG
+ else:
+ FROM = rffi.ULONGLONG
+ expected.insert(0,
+ "residual_call_irf_i $<* fn llong_to_int>, <Descr>, I[], R[], F[%f0] -> %i0")
+ expectedstr = '\n'.join(expected)
+ self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
+ transform=True)
+ elif TO in (rffi.LONG, rffi.ULONG):
+ if TO == rffi.LONG:
+ TO = rffi.LONGLONG
+ else:
+ TO = rffi.ULONGLONG
+ if rffi.cast(FROM, -1) < 0:
+ fnname = "llong_from_int"
+ else:
+ fnname = "llong_from_uint"
+ expected.pop() # remove int_return
+ expected.append(
+ "residual_call_irf_f $<* fn %s>, <Descr>, I[%s], R[], F[] -> %%f0"
+ % (fnname, returnvar))
+ expected.append("float_return %f0")
+ expectedstr = '\n'.join(expected)
+ self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
+ transform=True)
+
def test_force_cast_pointer(self):
from pypy.rpython.lltypesystem import rffi
def h(p):
@@ -813,6 +854,23 @@
int_return %i0
""", transform=True)
+ def test_force_cast_float(self):
+ from pypy.rpython.lltypesystem import rffi
+ def f(n):
+ return rffi.cast(lltype.Float, n)
+ self.encoding_test(f, [12.456], """
+ float_return %f0
+ """, transform=True)
+
+ def test_direct_ptradd(self):
+ from pypy.rpython.lltypesystem import rffi
+ def f(p, n):
+ return lltype.direct_ptradd(p, n)
+ self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """
+ int_add %i0, %i1 -> %i2
+ int_return %i2
+ """, transform=True)
+
def check_force_cast(FROM, TO, operations, value):
"""Check that the test is correctly written..."""
diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py
--- a/pypy/jit/codewriter/test/test_longlong.py
+++ b/pypy/jit/codewriter/test/test_longlong.py
@@ -37,7 +37,7 @@
class TestLongLong:
def setup_class(cls):
- if sys.maxint > 2147483647:
+ if longlong.is_64_bit:
py.test.skip("only for 32-bit platforms")
def do_check(self, opname, oopspecindex, ARGS, RESULT):
@@ -46,6 +46,8 @@
op = SpaceOperation(opname, vlist, v_result)
tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
op1 = tr.rewrite_operation(op)
+ if isinstance(op1, list):
+ [op1] = op1
#
def is_llf(TYPE):
return (TYPE == lltype.SignedLongLong or
@@ -196,6 +198,23 @@
for T2 in [lltype.Signed, lltype.Unsigned]:
self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT,
[T1], T2)
+ self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT,
+ [T1], T2)
+ if T2 == lltype.Signed:
+ expected = EffectInfo.OS_LLONG_FROM_INT
+ else:
+ expected = EffectInfo.OS_LLONG_FROM_UINT
+ self.do_check('cast_primitive', expected, [T2], T1)
+ self.do_check('force_cast', expected, [T2], T1)
+ #
+ for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+ for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+ vlist = [varoftype(T1)]
+ v_result = varoftype(T2)
+ op = SpaceOperation('force_cast', vlist, v_result)
+ tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ op1 = tr.rewrite_operation(op)
+ assert op1 is None
def test_constants(self):
for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -57,7 +57,6 @@
optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts,
inline_short_preamble, retraced)
-
if unroll:
optimize_unroll(metainterp_sd, loop, optimizations)
else:
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -4,7 +4,7 @@
from pypy.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeopt.util import _findall
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind
@@ -207,13 +207,7 @@
def propagate_forward(self, op):
if self.logops is not None:
debug_print(self.logops.repr_of_resop(op))
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.emit_operation(op)
+ dispatch_opt(self, op)
def _get_oopspec(self, op):
effectinfo = op.getdescr().get_extra_info()
@@ -224,4 +218,5 @@
def _get_funcval(self, op):
return self.getvalue(op.getarg(1))
-optimize_ops = _findall(OptFfiCall, 'optimize_')
+dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_',
+ default=OptFfiCall.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -1,5 +1,5 @@
import os
-from pypy.jit.metainterp.optimizeopt.util import _findall
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
from pypy.jit.metainterp.resoperation import rop, ResOperation
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.jitexc import JitException
@@ -76,7 +76,7 @@
self._cached_fields[structvalue] = fieldvalue
self._cached_fields_getfield_op[structvalue] = getfield_op
- def force_lazy_setfield(self, optheap):
+ def force_lazy_setfield(self, optheap, can_cache=True):
op = self._lazy_setfield
if op is not None:
# This is the way _lazy_setfield is usually reset to None.
@@ -86,12 +86,16 @@
self.clear()
self._lazy_setfield = None
optheap.next_optimization.propagate_forward(op)
+ if not can_cache:
+ return
# Once it is done, we can put at least one piece of information
# back in the cache: the value of this particular structure's
# field.
structvalue = optheap.getvalue(op.getarg(0))
fieldvalue = optheap.getvalue(op.getarglist()[-1])
self.remember_field_value(structvalue, fieldvalue, op)
+ elif not can_cache:
+ self.clear()
def clear(self):
self._cached_fields.clear()
@@ -248,20 +252,9 @@
for arraydescr in effectinfo.readonly_descrs_arrays:
self.force_lazy_setarrayitem(arraydescr)
for fielddescr in effectinfo.write_descrs_fields:
- self.force_lazy_setfield(fielddescr)
- try:
- cf = self.cached_fields[fielddescr]
- cf.clear()
- except KeyError:
- pass
+ self.force_lazy_setfield(fielddescr, can_cache=False)
for arraydescr in effectinfo.write_descrs_arrays:
- self.force_lazy_setarrayitem(arraydescr)
- try:
- submap = self.cached_arrayitems[arraydescr]
- for cf in submap.itervalues():
- cf.clear()
- except KeyError:
- pass
+ self.force_lazy_setarrayitem(arraydescr, can_cache=False)
if effectinfo.check_forces_virtual_or_virtualizable():
vrefinfo = self.optimizer.metainterp_sd.virtualref_info
self.force_lazy_setfield(vrefinfo.descr_forced)
@@ -284,20 +277,20 @@
if value in cf._cached_fields:
cf.turned_constant(newvalue, value)
- def force_lazy_setfield(self, descr):
+ def force_lazy_setfield(self, descr, can_cache=True):
try:
cf = self.cached_fields[descr]
except KeyError:
return
- cf.force_lazy_setfield(self)
+ cf.force_lazy_setfield(self, can_cache)
- def force_lazy_setarrayitem(self, arraydescr):
+ def force_lazy_setarrayitem(self, arraydescr, can_cache=True):
try:
submap = self.cached_arrayitems[arraydescr]
except KeyError:
return
for cf in submap.values():
- cf.force_lazy_setfield(self)
+ cf.force_lazy_setfield(self, can_cache)
def fixup_guard_situation(self):
# hackish: reverse the order of the last two operations if it makes
@@ -436,7 +429,7 @@
cf.do_setfield(self, op)
else:
# variable index, so make sure the lazy setarrayitems are done
- self.force_lazy_setarrayitem(op.getdescr())
+ self.force_lazy_setarrayitem(op.getdescr(), can_cache=False)
# and then emit the operation
self.emit_operation(op)
@@ -480,13 +473,7 @@
self._seen_guard_not_invalidated = True
self.emit_operation(op)
- def propagate_forward(self, op):
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.emit_operation(op)
-optimize_ops = _findall(OptHeap, 'optimize_')
+dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_',
+ default=OptHeap.emit_operation)
+OptHeap.propagate_forward = dispatch_opt
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -1,6 +1,6 @@
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0, \
MODE_ARRAY, MODE_STR, MODE_UNICODE
-from pypy.jit.metainterp.optimizeopt.util import _findall
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded,
IntLowerBound, IntUpperBound)
from pypy.jit.metainterp.history import Const, ConstInt
@@ -39,14 +39,11 @@
op = self.posponedop
self.posponedop = None
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- assert not op.is_ovf()
- self.emit_operation(op)
+ dispatch_opt(self, op)
+
+ def opt_default(self, op):
+ assert not op.is_ovf()
+ self.emit_operation(op)
def propagate_bounds_backward(self, box):
@@ -62,11 +59,7 @@
op = self.optimizer.producer[box]
except KeyError:
return
- opnum = op.getopnum()
- for value, func in propagate_bounds_ops:
- if opnum == value:
- func(self, op)
- break
+ dispatch_bounds_ops(self, op)
def optimize_GUARD_TRUE(self, op):
self.emit_operation(op)
@@ -462,5 +455,6 @@
propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL
-optimize_ops = _findall(OptIntBounds, 'optimize_')
-propagate_bounds_ops = _findall(OptIntBounds, 'propagate_bounds_')
+dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_',
+ default=OptIntBounds.opt_default)
+dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_')
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -4,7 +4,7 @@
from pypy.jit.metainterp.resoperation import rop, ResOperation
from pypy.jit.metainterp import jitprof
from pypy.jit.metainterp.executor import execute_nonspec
-from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method, sort_descrs
from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, args_dict
from pypy.jit.metainterp.optimize import InvalidLoop
from pypy.jit.metainterp import resume, compile
@@ -564,14 +564,7 @@
def propagate_forward(self, op):
self.producer[op.result] = op
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.optimize_default(op)
- #print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n'
+ dispatch_opt(self, op)
def test_emittable(self, op):
return True
@@ -723,7 +716,8 @@
-optimize_ops = _findall(Optimizer, 'optimize_')
+dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_',
+ default=Optimizer.optimize_default)
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -1,7 +1,7 @@
from pypy.jit.metainterp.optimizeopt.optimizer import *
from pypy.jit.metainterp.resoperation import opboolinvers, opboolreflex
from pypy.jit.metainterp.history import ConstInt
-from pypy.jit.metainterp.optimizeopt.util import _findall
+from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method
from pypy.jit.metainterp.resoperation import rop, ResOperation
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.metainterp.optimizeopt.intutils import IntBound
@@ -36,18 +36,13 @@
if self.find_rewritable_bool(op, args):
return
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.emit_operation(op)
+ dispatch_opt(self, op)
def test_emittable(self, op):
opnum = op.getopnum()
- for value, func in optimize_guards:
+ for value, cls, func in optimize_guards:
if opnum == value:
+ assert isinstance(op, cls)
try:
func(self, op, dryrun=True)
return self.is_emittable(op)
@@ -219,6 +214,7 @@
))
return
self.emit_operation(op)
+ self.pure(rop.FLOAT_MUL, [arg2, arg1], op.result)
def optimize_FLOAT_NEG(self, op):
v1 = op.getarg(0)
@@ -494,5 +490,6 @@
self.emit_operation(op)
-optimize_ops = _findall(OptRewrite, 'optimize_')
+dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
+ default=OptRewrite.emit_operation)
optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -1,7 +1,7 @@
from pypy.jit.metainterp.resoperation import ResOperation, rop
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
-from pypy.jit.metainterp.optimizeopt.util import _findall
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
class OptSimplify(Optimization):
def optimize_CALL_PURE(self, op):
@@ -25,13 +25,7 @@
# but it's a bit hard to implement robustly if heap.py is also run
pass
- def propagate_forward(self, op):
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.emit_operation(op)
-optimize_ops = _findall(OptSimplify, 'optimize_')
+dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
+ default=OptSimplify.emit_operation)
+OptSimplify.propagate_forward = dispatch_opt
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -1755,6 +1755,48 @@
"""
self.optimize_loop(ops, expected)
+ def test_duplicate_getarrayitem_after_setarrayitem_bug(self):
+ ops = """
+ [p0, i0, i1]
+ setarrayitem_gc(p0, 0, i0, descr=arraydescr)
+ i6 = int_add(i0, 1)
+ setarrayitem_gc(p0, i1, i6, descr=arraydescr)
+ i10 = getarrayitem_gc(p0, 0, descr=arraydescr)
+ i11 = int_add(i10, i0)
+ jump(p0, i11, i1)
+ """
+ expected = """
+ [p0, i0, i1]
+ i6 = int_add(i0, 1)
+ setarrayitem_gc(p0, 0, i0, descr=arraydescr)
+ setarrayitem_gc(p0, i1, i6, descr=arraydescr)
+ i10 = getarrayitem_gc(p0, 0, descr=arraydescr)
+ i11 = int_add(i10, i0)
+ jump(p0, i11, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getarrayitem_after_setarrayitem_bug2(self):
+ ops = """
+ [p0, i0, i1]
+ i2 = getarrayitem_gc(p0, 0, descr=arraydescr)
+ i6 = int_add(i0, 1)
+ setarrayitem_gc(p0, i1, i6, descr=arraydescr)
+ i10 = getarrayitem_gc(p0, 0, descr=arraydescr)
+ i11 = int_add(i10, i2)
+ jump(p0, i11, i1)
+ """
+ expected = """
+ [p0, i0, i1]
+ i2 = getarrayitem_gc(p0, 0, descr=arraydescr)
+ i6 = int_add(i0, 1)
+ setarrayitem_gc(p0, i1, i6, descr=arraydescr)
+ i10 = getarrayitem_gc(p0, 0, descr=arraydescr)
+ i11 = int_add(i10, i2)
+ jump(p0, i11, i1)
+ """
+ self.optimize_loop(ops, expected)
+
def test_bug_1(self):
ops = """
[i0, p1]
@@ -3916,11 +3958,8 @@
i2 = strlen(p2)
i3 = int_add(i1, i2)
p3 = newstr(i3)
- i4 = strlen(p1)
- copystrcontent(p1, p3, 0, 0, i4)
- i5 = strlen(p2)
- i6 = int_add(i4, i5) # will be killed by the backend
- copystrcontent(p2, p3, 0, i4, i5)
+ copystrcontent(p1, p3, 0, 0, i1)
+ copystrcontent(p2, p3, 0, i1, i2)
jump(p2, p3)
"""
self.optimize_strunicode_loop(ops, expected)
@@ -3941,9 +3980,7 @@
p3 = newstr(i3)
strsetitem(p3, 0, i0)
strsetitem(p3, 1, i1)
- i4 = strlen(p2)
- i5 = int_add(2, i4) # will be killed by the backend
- copystrcontent(p2, p3, 0, 2, i4)
+ copystrcontent(p2, p3, 0, 2, i2)
jump(i1, i0, p3)
"""
self.optimize_strunicode_loop(ops, expected)
@@ -3962,10 +3999,9 @@
i2 = strlen(p2)
i3 = int_add(i2, 2)
p3 = newstr(i3)
- i4 = strlen(p2)
- copystrcontent(p2, p3, 0, 0, i4)
- strsetitem(p3, i4, i0)
- i5 = int_add(i4, 1)
+ copystrcontent(p2, p3, 0, 0, i2)
+ strsetitem(p3, i2, i0)
+ i5 = int_add(i2, 1)
strsetitem(p3, i5, i1)
i6 = int_add(i5, 1) # will be killed by the backend
jump(i1, i0, p3)
@@ -3987,14 +4023,9 @@
i3 = strlen(p3)
i123 = int_add(i12, i3)
p5 = newstr(i123)
- i1b = strlen(p1)
- copystrcontent(p1, p5, 0, 0, i1b)
- i2b = strlen(p2)
- i12b = int_add(i1b, i2b)
- copystrcontent(p2, p5, 0, i1b, i2b)
- i3b = strlen(p3)
- i123b = int_add(i12b, i3b) # will be killed by the backend
- copystrcontent(p3, p5, 0, i12b, i3b)
+ copystrcontent(p1, p5, 0, 0, i1)
+ copystrcontent(p2, p5, 0, i1, i2)
+ copystrcontent(p3, p5, 0, i12, i3)
jump(p2, p3, p5)
"""
self.optimize_strunicode_loop(ops, expected)
@@ -4010,10 +4041,8 @@
i2 = strlen(p2)
i3 = int_add(i2, 1)
p3 = newstr(i3)
- i4 = strlen(p2)
- copystrcontent(p2, p3, 0, 0, i4)
- strsetitem(p3, i4, 120) # == ord('x')
- i5 = int_add(i4, 1) # will be killed by the backend
+ copystrcontent(p2, p3, 0, 0, i2)
+ strsetitem(p3, i2, 120) # == ord('x')
jump(p3)
"""
self.optimize_strunicode_loop(ops, expected)
@@ -4131,9 +4160,7 @@
i5 = int_add(i3, i4)
p4 = newstr(i5)
copystrcontent(p1, p4, i1, 0, i3)
- i4b = strlen(p2)
- i6 = int_add(i3, i4b) # killed by the backend
- copystrcontent(p2, p4, 0, i3, i4b)
+ copystrcontent(p2, p4, 0, i3, i4)
jump(p4, i1, i2, p2)
"""
self.optimize_strunicode_loop(ops, expected)
@@ -4178,11 +4205,8 @@
i2 = strlen(p2)
i3 = int_add(i1, i2)
p4 = newstr(i3)
- i4 = strlen(p1)
- copystrcontent(p1, p4, 0, 0, i4)
- i5 = strlen(p2)
- i6 = int_add(i4, i5) # will be killed by the backend
- copystrcontent(p2, p4, 0, i4, i5)
+ copystrcontent(p1, p4, 0, 0, i1)
+ copystrcontent(p2, p4, 0, i1, i2)
i0 = call(0, p3, p4, descr=strequaldescr)
escape(i0)
jump(p1, p2, p3)
@@ -4374,11 +4398,8 @@
i2 = strlen(p2)
i3 = int_add(i1, i2)
p4 = newstr(i3)
- i4 = strlen(p1)
- copystrcontent(p1, p4, 0, 0, i4)
- i5 = strlen(p2)
- i6 = int_add(i4, i5) # will be killed by the backend
- copystrcontent(p2, p4, 0, i4, i5)
+ copystrcontent(p1, p4, 0, 0, i1)
+ copystrcontent(p2, p4, 0, i1, i2)
i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr)
escape(i0)
jump(p1, p2)
@@ -4532,6 +4553,39 @@
"""
self.optimize_loop(ops, expected)
+ def test_strslice_subtraction_folds(self):
+ ops = """
+ [p0, i0]
+ i1 = int_add(i0, 1)
+ p1 = call(0, p0, i0, i1, descr=strslicedescr)
+ escape(p1)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i0]
+ i1 = int_add(i0, 1)
+ p1 = newstr(1)
+ i2 = strgetitem(p0, i0)
+ strsetitem(p1, 0, i2)
+ escape(p1)
+ jump(p0, i1)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_float_mul_reversed(self):
+ ops = """
+ [f0, f1]
+ f2 = float_mul(f0, f1)
+ f3 = float_mul(f1, f0)
+ jump(f2, f3)
+ """
+ expected = """
+ [f0, f1]
+ f2 = float_mul(f0, f1)
+ jump(f2, f2)
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
pass
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -3074,11 +3074,11 @@
def test_residual_call_invalidate_some_arrays(self):
ops = """
[p1, p2, i1]
- p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p3 = getarrayitem_gc(p2, 0, descr=arraydescr2)
p4 = getarrayitem_gc(p2, 1, descr=arraydescr2)
i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
i3 = call(i1, descr=writearraydescr)
- p5 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p5 = getarrayitem_gc(p2, 0, descr=arraydescr2)
p6 = getarrayitem_gc(p2, 1, descr=arraydescr2)
i4 = getarrayitem_gc(p1, 1, descr=arraydescr)
escape(p3)
@@ -3091,7 +3091,7 @@
"""
expected = """
[p1, p2, i1]
- p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p3 = getarrayitem_gc(p2, 0, descr=arraydescr2)
p4 = getarrayitem_gc(p2, 1, descr=arraydescr2)
i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
i3 = call(i1, descr=writearraydescr)
@@ -5343,11 +5343,8 @@
i2 = strlen(p2)
i3 = int_add(i1, i2)
p3 = newstr(i3)
- i4 = strlen(p1)
- copystrcontent(p1, p3, 0, 0, i4)
- i5 = strlen(p2)
- i6 = int_add(i4, i5) # will be killed by the backend
- copystrcontent(p2, p3, 0, i4, i5)
+ copystrcontent(p1, p3, 0, 0, i1)
+ copystrcontent(p2, p3, 0, i1, i2)
jump(p2, p3)
"""
self.optimize_strunicode_loop(ops, expected, expected)
@@ -5368,9 +5365,7 @@
p3 = newstr(i3)
strsetitem(p3, 0, i0)
strsetitem(p3, 1, i1)
- i4 = strlen(p2)
- i5 = int_add(2, i4) # will be killed by the backend
- copystrcontent(p2, p3, 0, 2, i4)
+ copystrcontent(p2, p3, 0, 2, i2)
jump(i1, i0, p3)
"""
self.optimize_strunicode_loop(ops, expected, expected)
@@ -5389,10 +5384,9 @@
i2 = strlen(p2)
i3 = int_add(i2, 2)
p3 = newstr(i3)
- i4 = strlen(p2)
- copystrcontent(p2, p3, 0, 0, i4)
- strsetitem(p3, i4, i0)
- i5 = int_add(i4, 1)
+ copystrcontent(p2, p3, 0, 0, i2)
+ strsetitem(p3, i2, i0)
+ i5 = int_add(i2, 1)
strsetitem(p3, i5, i1)
i6 = int_add(i5, 1) # will be killed by the backend
jump(i1, i0, p3)
@@ -5414,14 +5408,9 @@
i3 = strlen(p3)
i123 = int_add(i12, i3)
p5 = newstr(i123)
- i1b = strlen(p1)
- copystrcontent(p1, p5, 0, 0, i1b)
- i2b = strlen(p2)
- i12b = int_add(i1b, i2b)
- copystrcontent(p2, p5, 0, i1b, i2b)
- i3b = strlen(p3)
- i123b = int_add(i12b, i3b) # will be killed by the backend
- copystrcontent(p3, p5, 0, i12b, i3b)
+ copystrcontent(p1, p5, 0, 0, i1)
+ copystrcontent(p2, p5, 0, i1, i2)
+ copystrcontent(p3, p5, 0, i12, i3)
jump(p2, p3, p5)
"""
self.optimize_strunicode_loop(ops, expected, expected)
@@ -5437,10 +5426,8 @@
i2 = strlen(p2)
i3 = int_add(i2, 1)
p3 = newstr(i3)
- i4 = strlen(p2)
- copystrcontent(p2, p3, 0, 0, i4)
- strsetitem(p3, i4, 120) # == ord('x')
- i5 = int_add(i4, 1) # will be killed by the backend
+ copystrcontent(p2, p3, 0, 0, i2)
+ strsetitem(p3, i2, 120) # == ord('x')
jump(p3)
"""
self.optimize_strunicode_loop(ops, expected, expected)
@@ -5599,9 +5586,7 @@
i5 = int_add(i3, i4)
p4 = newstr(i5)
copystrcontent(p1, p4, i1, 0, i3)
- i4b = strlen(p2)
- i6 = int_add(i3, i4b) # killed by the backend
- copystrcontent(p2, p4, 0, i3, i4b)
+ copystrcontent(p2, p4, 0, i3, i4)
jump(p4, i1, i2, p2)
"""
self.optimize_strunicode_loop(ops, expected, expected)
@@ -5711,11 +5696,8 @@
i2 = strlen(p2)
i3 = int_add(i1, i2)
p4 = newstr(i3)
- i4 = strlen(p1)
- copystrcontent(p1, p4, 0, 0, i4)
- i5 = strlen(p2)
- i6 = int_add(i4, i5) # will be killed by the backend
- copystrcontent(p2, p4, 0, i4, i5)
+ copystrcontent(p1, p4, 0, 0, i1)
+ copystrcontent(p2, p4, 0, i1, i2)
i0 = call(0, p3, p4, descr=strequaldescr)
escape(i0)
jump(p1, p2, p3)
@@ -5939,11 +5921,8 @@
i2 = strlen(p2)
i3 = int_add(i1, i2)
p4 = newstr(i3)
- i4 = strlen(p1)
- copystrcontent(p1, p4, 0, 0, i4)
- i5 = strlen(p2)
- i6 = int_add(i4, i5) # will be killed by the backend
- copystrcontent(p2, p4, 0, i4, i5)
+ copystrcontent(p1, p4, 0, 0, i1)
+ copystrcontent(p2, p4, 0, i1, i2)
i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr)
escape(i0)
jump(p1, p2)
diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py
--- a/pypy/jit/metainterp/optimizeopt/util.py
+++ b/pypy/jit/metainterp/optimizeopt/util.py
@@ -20,9 +20,25 @@
if op_prefix and not name.startswith(op_prefix):
continue
if hasattr(Class, name_prefix + name):
- result.append((value, getattr(Class, name_prefix + name)))
+ opclass = resoperation.opclasses[getattr(rop, name)]
+ assert name in opclass.__name__
+ result.append((value, opclass, getattr(Class, name_prefix + name)))
return unrolling_iterable(result)
+def make_dispatcher_method(Class, name_prefix, op_prefix=None, default=None):
+ ops = _findall(Class, name_prefix, op_prefix)
+ def dispatch(self, op, *args):
+ opnum = op.getopnum()
+ for value, cls, func in ops:
+ if opnum == value:
+ assert isinstance(op, cls)
+ return func(self, op, *args)
+ if default:
+ return default(self, op, *args)
+ dispatch.func_name = "dispatch_" + name_prefix
+ return dispatch
+
+
def partition(array, left, right):
last_item = array[right]
pivot = last_item.sort_key()
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -1,7 +1,7 @@
from pypy.jit.metainterp.history import Const, ConstInt, BoxInt
from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeopt.util import _findall, sort_descrs
-from pypy.jit.metainterp.optimizeopt.util import descrlist_dict
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from pypy.jit.metainterp.optimizeopt.util import descrlist_dict, sort_descrs
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.optimizeopt import optimizer
from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
@@ -475,13 +475,8 @@
###self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue)
self.emit_operation(op)
- def propagate_forward(self, op):
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.emit_operation(op)
-optimize_ops = _findall(OptVirtualize, 'optimize_')
+dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_',
+ default=OptVirtualize.emit_operation)
+
+OptVirtualize.propagate_forward = dispatch_opt
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -8,7 +8,7 @@
from pypy.jit.metainterp.optimizeopt import optimizer, virtualize
from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
from pypy.jit.metainterp.optimizeopt.optimizer import llhelper
-from pypy.jit.metainterp.optimizeopt.util import _findall
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter import heaptracker
from pypy.rlib.unroll import unrolling_iterable
@@ -61,7 +61,7 @@
self.ensure_nonnull()
box = self.force_box()
lengthbox = BoxInt()
- optimization.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox))
+ optimization.optimize_default(ResOperation(mode.STRLEN, [box], lengthbox))
return lengthbox
@specialize.arg(1)
@@ -72,13 +72,13 @@
else:
return None
- def string_copy_parts(self, optimization, targetbox, offsetbox, mode):
+ def string_copy_parts(self, optimizer, targetbox, offsetbox, mode):
# Copies the pointer-to-string 'self' into the target string
# given by 'targetbox', at the specified offset. Returns the offset
# at the end of the copy.
- lengthbox = self.getstrlen(optimization, mode)
+ lengthbox = self.getstrlen(optimizer, mode)
srcbox = self.force_box()
- return copy_str_content(optimization, srcbox, targetbox,
+ return copy_str_content(optimizer, srcbox, targetbox,
CONST_0, offsetbox, lengthbox, mode)
@@ -335,7 +335,7 @@
if optimizer is None:
return None
resbox = BoxInt()
- optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox))
+ optimizer.optimize_default(ResOperation(rop.INT_ADD, [box1, box2], resbox))
return resbox
def _int_sub(optimizer, box1, box2):
@@ -345,10 +345,10 @@
if isinstance(box1, ConstInt):
return ConstInt(box1.value - box2.value)
resbox = BoxInt()
- optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox))
+ optimizer.optimize_default(ResOperation(rop.INT_SUB, [box1, box2], resbox))
return resbox
-def _strgetitem(optimization, strbox, indexbox, mode):
+def _strgetitem(optimizer, strbox, indexbox, mode):
if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt):
if mode is mode_string:
s = strbox.getref(lltype.Ptr(rstr.STR))
@@ -357,7 +357,7 @@
s = strbox.getref(lltype.Ptr(rstr.UNICODE))
return ConstInt(ord(s.chars[indexbox.getint()]))
resbox = BoxInt()
- optimization.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox],
+ optimizer.optimize_default(ResOperation(mode.STRGETITEM, [strbox, indexbox],
resbox))
return resbox
@@ -443,7 +443,7 @@
if vindex.is_constant():
return value.getitem(vindex.box.getint())
#
- resbox = _strgetitem(self, value.force_box(), vindex.force_box(), mode)
+ resbox = _strgetitem(self.optimizer, value.force_box(), vindex.force_box(), mode)
return self.getvalue(resbox)
def optimize_STRLEN(self, op):
@@ -453,7 +453,7 @@
def _optimize_STRLEN(self, op, mode):
value = self.getvalue(op.getarg(0))
- lengthbox = value.getstrlen(self, mode)
+ lengthbox = value.getstrlen(self.optimizer, mode)
self.make_equal_to(op.result, self.getvalue(lengthbox))
def optimize_CALL(self, op):
@@ -652,16 +652,11 @@
self.emit_operation(op)
return
- opnum = op.getopnum()
- for value, func in optimize_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.emit_operation(op)
+ dispatch_opt(self, op)
-optimize_ops = _findall(OptString, 'optimize_')
+dispatch_opt = make_dispatcher_method(OptString, 'optimize_',
+ default=OptString.emit_operation)
def _findall_call_oopspec():
prefix = 'opt_call_stroruni_'
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
@@ -56,6 +56,8 @@
# for resume.py operation
self.parent_resumedata_snapshot = None
self.parent_resumedata_frame_info_list = None
+ # counter for unrolling inlined loops
+ self.unroll_iterations = 1
@specialize.arg(3)
def copy_constants(self, registers, constants, ConstClass):
@@ -310,26 +312,27 @@
self.opimpl_goto_if_not(condbox, target)
''' % (_opimpl, _opimpl.upper())).compile()
+
+ def _establish_nullity(self, box, orgpc):
+ value = box.nonnull()
+ if value:
+ if box not in self.metainterp.known_class_boxes:
+ self.generate_guard(rop.GUARD_NONNULL, box, resumepc=orgpc)
+ else:
+ if not isinstance(box, Const):
+ self.generate_guard(rop.GUARD_ISNULL, box, resumepc=orgpc)
+ promoted_box = box.constbox()
+ self.metainterp.replace_box(box, promoted_box)
+ return value
+
@arguments("orgpc", "box", "label")
def opimpl_goto_if_not_ptr_nonzero(self, orgpc, box, target):
- value = box.nonnull()
- if value:
- opnum = rop.GUARD_NONNULL
- else:
- opnum = rop.GUARD_ISNULL
- self.generate_guard(opnum, box, resumepc=orgpc)
- if not value:
+ if not self._establish_nullity(box, orgpc):
self.pc = target
@arguments("orgpc", "box", "label")
def opimpl_goto_if_not_ptr_iszero(self, orgpc, box, target):
- value = box.nonnull()
- if value:
- opnum = rop.GUARD_NONNULL
- else:
- opnum = rop.GUARD_ISNULL
- self.generate_guard(opnum, box, resumepc=orgpc)
- if value:
+ if self._establish_nullity(box, orgpc):
self.pc = target
@arguments("box", "box", "box")
@@ -364,7 +367,9 @@
def opimpl_new_with_vtable(self, sizedescr):
cpu = self.metainterp.cpu
cls = heaptracker.descr2vtable(cpu, sizedescr)
- return self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls))
+ resbox = self.execute(rop.NEW_WITH_VTABLE, ConstInt(cls))
+ self.metainterp.known_class_boxes[resbox] = None
+ return resbox
## @FixME #arguments("box")
## def opimpl_runtimenew(self, classbox):
@@ -387,8 +392,21 @@
@arguments("box", "descr", "box")
def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox):
- return self.execute_with_descr(rop.GETARRAYITEM_GC,
- arraydescr, arraybox, indexbox)
+ cache = self.metainterp.heap_array_cache.get(arraydescr, None)
+ if cache and isinstance(indexbox, ConstInt):
+ index = indexbox.getint()
+ frombox, tobox = cache.get(index, (None, None))
+ if frombox is arraybox:
+ return tobox
+ resbox = self.execute_with_descr(rop.GETARRAYITEM_GC,
+ arraydescr, arraybox, indexbox)
+ if isinstance(indexbox, ConstInt):
+ if not cache:
+ cache = self.metainterp.heap_array_cache[arraydescr] = {}
+ index = indexbox.getint()
+ cache[index] = arraybox, resbox
+ return resbox
+
opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any
opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any
@@ -416,6 +434,13 @@
indexbox, itembox):
self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox,
indexbox, itembox)
+ if isinstance(indexbox, ConstInt):
+ cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {})
+ cache[indexbox.getint()] = arraybox, itembox
+ else:
+ cache = self.metainterp.heap_array_cache.get(arraydescr, None)
+ if cache:
+ cache.clear()
opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any
opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any
@@ -451,21 +476,17 @@
def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr,
sizebox):
sbox = self.metainterp.execute_and_record(rop.NEW, structdescr)
- self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr,
- sbox, sizebox)
+ self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox)
abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr,
sizebox)
- self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr,
- sbox, abox)
+ self._opimpl_setfield_gc_any(sbox, itemsdescr, abox)
return sbox
@arguments("box", "descr", "descr", "box")
def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr,
indexbox):
- arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
- itemsdescr, listbox)
- return self.execute_with_descr(rop.GETARRAYITEM_GC,
- arraydescr, arraybox, indexbox)
+ arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr)
+ return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox)
opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any
opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any
@@ -474,10 +495,9 @@
@arguments("box", "descr", "descr", "box", "box")
def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr,
indexbox, valuebox):
- arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
- itemsdescr, listbox)
- self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox,
- indexbox, valuebox)
+ arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr)
+ self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox,
+ valuebox)
opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any
opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any
@@ -499,18 +519,29 @@
@arguments("box", "descr")
def _opimpl_getfield_gc_any(self, box, fielddescr):
- return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box)
+ return self._opimpl_getfield_gc_any_pureornot(
+ rop.GETFIELD_GC, box, fielddescr)
opimpl_getfield_gc_i = _opimpl_getfield_gc_any
opimpl_getfield_gc_r = _opimpl_getfield_gc_any
opimpl_getfield_gc_f = _opimpl_getfield_gc_any
@arguments("box", "descr")
def _opimpl_getfield_gc_pure_any(self, box, fielddescr):
- return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box)
+ return self._opimpl_getfield_gc_any_pureornot(
+ rop.GETFIELD_GC_PURE, box, fielddescr)
opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any
opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any
opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any
+ @specialize.arg(1)
+ def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr):
+ frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None))
+ if frombox is box:
+ return tobox
+ resbox = self.execute_with_descr(opnum, fielddescr, box)
+ self.metainterp.heap_cache[fielddescr] = (box, resbox)
+ return resbox
+
@arguments("orgpc", "box", "descr")
def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr):
ginfo = self.metainterp.jitdriver_sd.greenfield_info
@@ -529,7 +560,11 @@
@arguments("box", "descr", "box")
def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox):
+ frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None))
+ if frombox is box and tobox is valuebox:
+ return
self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
+ self.metainterp.heap_cache[fielddescr] = (box, valuebox)
opimpl_setfield_gc_i = _opimpl_setfield_gc_any
opimpl_setfield_gc_r = _opimpl_setfield_gc_any
opimpl_setfield_gc_f = _opimpl_setfield_gc_any
@@ -593,12 +628,16 @@
standard_box = self.metainterp.virtualizable_boxes[-1]
if standard_box is box:
return False
+ if box in self.metainterp.nonstandard_virtualizables:
+ return True
eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None,
box, standard_box)
eqbox = self.implement_guard_value(pc, eqbox)
isstandard = eqbox.getint()
if isstandard:
self.metainterp.replace_box(box, standard_box)
+ else:
+ self.metainterp.nonstandard_virtualizables[box] = None
return not isstandard
def _get_virtualizable_field_index(self, fielddescr):
@@ -610,7 +649,7 @@
@arguments("orgpc", "box", "descr")
def _opimpl_getfield_vable(self, pc, box, fielddescr):
if self._nonstandard_virtualizable(pc, box):
- return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box)
+ return self._opimpl_getfield_gc_any(box, fielddescr)
self.metainterp.check_synchronized_virtualizable()
index = self._get_virtualizable_field_index(fielddescr)
return self.metainterp.virtualizable_boxes[index]
@@ -622,8 +661,7 @@
@arguments("orgpc", "box", "descr", "box")
def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox):
if self._nonstandard_virtualizable(pc, box):
- self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
- return
+ return self._opimpl_setfield_gc_any(box, fielddescr, valuebox)
index = self._get_virtualizable_field_index(fielddescr)
self.metainterp.virtualizable_boxes[index] = valuebox
self.metainterp.synchronize_virtualizable()
@@ -653,10 +691,8 @@
@arguments("orgpc", "box", "descr", "descr", "box")
def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox):
if self._nonstandard_virtualizable(pc, box):
- arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
- fdescr, box)
- return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr,
- arraybox, indexbox)
+ arraybox = self._opimpl_getfield_gc_any(box, fdescr)
+ return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox)
self.metainterp.check_synchronized_virtualizable()
index = self._get_arrayitem_vable_index(pc, fdescr, indexbox)
return self.metainterp.virtualizable_boxes[index]
@@ -669,10 +705,9 @@
def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox,
valuebox):
if self._nonstandard_virtualizable(pc, box):
- arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
- fdescr, box)
- self.execute_with_descr(rop.SETARRAYITEM_GC, adescr,
- arraybox, indexbox, valuebox)
+ arraybox = self._opimpl_getfield_gc_any(box, fdescr)
+ self._opimpl_setarrayitem_gc_any(arraybox, adescr,
+ indexbox, valuebox)
return
index = self._get_arrayitem_vable_index(pc, fdescr, indexbox)
self.metainterp.virtualizable_boxes[index] = valuebox
@@ -686,8 +721,7 @@
@arguments("orgpc", "box", "descr", "descr")
def opimpl_arraylen_vable(self, pc, box, fdescr, adescr):
if self._nonstandard_virtualizable(pc, box):
- arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
- fdescr, box)
+ arraybox = self._opimpl_getfield_gc_any(box, fdescr)
return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox)
vinfo = self.metainterp.jitdriver_sd.virtualizable_info
virtualizable_box = self.metainterp.virtualizable_boxes[-1]
@@ -845,7 +879,9 @@
@arguments("orgpc", "box")
def opimpl_guard_class(self, orgpc, box):
clsbox = self.cls_of_box(box)
- self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc)
+ if box not in self.metainterp.known_class_boxes:
+ self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc)
+ self.metainterp.known_class_boxes[box] = None
return clsbox
@arguments("int", "orgpc")
@@ -897,6 +933,10 @@
# 'redboxes' back into the registers where it comes from.
put_back_list_of_boxes3(self, jcposition, redboxes)
else:
+ if jitdriver_sd.warmstate.should_unroll_one_iteration(greenboxes):
+ if self.unroll_iterations > 0:
+ self.unroll_iterations -= 1
+ return
# warning! careful here. We have to return from the current
# frame containing the jit_merge_point, and then use
# do_recursive_call() to follow the recursive call. This is
@@ -1128,13 +1168,11 @@
metainterp.jitdriver_sd.greenfield_info is not None):
virtualizable_boxes = metainterp.virtualizable_boxes
saved_pc = self.pc
- try:
- if resumepc >= 0:
- self.pc = resumepc
- resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
- metainterp.virtualref_boxes, resumedescr)
- finally:
- self.pc = saved_pc
+ if resumepc >= 0:
+ self.pc = resumepc
+ resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
+ metainterp.virtualref_boxes, resumedescr)
+ self.pc = saved_pc
def implement_guard_value(self, orgpc, box):
"""Promote the given Box into a Const. Note: be careful, it's a
@@ -1449,6 +1487,16 @@
self.last_exc_value_box = None
self.retracing_loop_from = None
self.call_pure_results = args_dict_box()
+ # contains boxes where the class is already known
+ self.known_class_boxes = {}
+ # contains frame boxes that are not virtualizables
+ self.nonstandard_virtualizables = {}
+ # heap cache
+ # maps descrs to (from_box, to_box) tuples
+ self.heap_cache = {}
+ # heap array cache
+ # maps descrs to {index: (from_box, to_box)} dicts
+ self.heap_array_cache = {}
def perform_call(self, jitcode, boxes, greenkey=None):
# causes the metainterp to enter the given subfunction
@@ -1624,10 +1672,27 @@
# record the operation
profiler = self.staticdata.profiler
profiler.count_ops(opnum, RECORDED_OPS)
+ self._invalidate_caches(opnum, descr)
op = self.history.record(opnum, argboxes, resbox, descr)
self.attach_debug_info(op)
return resbox
+ def _invalidate_caches(self, opnum, descr):
+ if opnum == rop.SETFIELD_GC:
+ return
+ if opnum == rop.SETARRAYITEM_GC:
+ return
+ if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST:
+ return
+ if opnum == rop.CALL:
+ effectinfo = descr.get_extra_info()
+ if effectinfo.extraeffect == effectinfo.EF_ELIDABLE:
+ return
+ if self.heap_cache:
+ self.heap_cache.clear()
+ if self.heap_array_cache:
+ self.heap_array_cache.clear()
+
def attach_debug_info(self, op):
if (not we_are_translated() and op is not None
and getattr(self, 'framestack', None)):
@@ -1789,6 +1854,11 @@
duplicates[box] = None
def reached_loop_header(self, greenboxes, redboxes, resumedescr):
+ self.known_class_boxes = {}
+ self.nonstandard_virtualizables = {} # XXX maybe not needed?
+ self.heap_cache = {}
+ self.heap_array_cache = {}
+
duplicates = {}
self.remove_consts_and_duplicates(redboxes, len(redboxes),
duplicates)
@@ -2295,6 +2365,16 @@
for i in range(len(boxes)):
if boxes[i] is oldbox:
boxes[i] = newbox
+ for descr, (frombox, tobox) in self.heap_cache.iteritems():
+ change = False
+ if frombox is oldbox:
+ change = True
+ frombox = newbox
+ if tobox is oldbox:
+ change = True
+ tobox = newbox
+ if change:
+ self.heap_cache[descr] = frombox, tobox
def find_biggest_function(self):
start_stack = []
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
@@ -281,9 +281,6 @@
assert len(args) == 2
self._arg0, self._arg1 = args
- def getarglist(self):
- return [self._arg0, self._arg1, self._arg2]
-
def numargs(self):
return 2
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
@@ -11,7 +11,7 @@
from pypy import conftest
from pypy.rlib.rarithmetic import ovfcheck
from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.ootypesystem import ootype
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
@@ -542,6 +542,32 @@
assert res == 84 - 61 - 62
self.check_history(call=1) # because the trace starts immediately
+ def test_unroll_one_loop_iteration(self):
+ def unroll(code):
+ return code == 0
+ myjitdriver = JitDriver(greens = ['code'],
+ reds = ['loops', 'inner_loops', 's'],
+ should_unroll_one_iteration=unroll)
+
+ def f(code, loops, inner_loops):
+ s = 0
+ while loops > 0:
+ myjitdriver.jit_merge_point(code=code, loops=loops,
+ inner_loops=inner_loops, s=s)
+ if code == 1:
+ s += f(0, inner_loops, 0)
+ loops -= 1
+ s += 1
+ return s
+
+ res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True)
+ assert res == f(1, 4, 1)
+ self.check_history(call_assembler=0)
+
+ res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True)
+ assert res == f(1, 4, 2)
+ self.check_history(call_assembler=1)
+
def test_format(self):
def f(n):
return len("<%d>" % n)
@@ -1018,11 +1044,14 @@
pass
class B(A):
pass
+ @dont_look_inside
+ def extern(n):
+ if n:
+ return A()
+ else:
+ return B()
def fn(n):
- if n:
- obj = A()
- else:
- obj = B()
+ obj = extern(n)
return isinstance(obj, B)
res = self.interp_operations(fn, [0])
assert res
@@ -1055,6 +1084,7 @@
res = self.meta_interp(main, [])
assert res == 55
+
def test_assert_isinstance(self):
class A:
pass
@@ -1215,7 +1245,7 @@
return tup[1]
res = self.interp_operations(f, [3, 5])
assert res == 5
- self.check_operations_history(setfield_gc=2, getfield_gc_pure=1)
+ self.check_operations_history(setfield_gc=2, getfield_gc_pure=0)
def test_oosend_look_inside_only_one(self):
class A:
@@ -1583,8 +1613,6 @@
assert res == 1
def test_raw_malloc_and_access(self):
- from pypy.rpython.lltypesystem import rffi
-
TP = rffi.CArray(lltype.Signed)
def f(n):
@@ -1598,8 +1626,6 @@
assert res == 10
def test_raw_malloc_and_access_float(self):
- from pypy.rpython.lltypesystem import rffi
-
TP = rffi.CArray(lltype.Float)
def f(n, f):
@@ -2130,7 +2156,7 @@
myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa)
if 0 < a <= 5: pass
if 0 < b <= 5: pass
- sa += (((((a << b) << b) << b) >> b) >> b) >> b
+ sa += (((((a << b) << b) << b) >> b) >> b) >> b
n += 1
return sa
@@ -2140,10 +2166,10 @@
myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa)
if 0 < a < promote(sys.maxint/2): pass
if 0 < b < 100: pass
- sa += (((((a << b) << b) << b) >> b) >> b) >> b
+ sa += (((((a << b) << b) << b) >> b) >> b) >> b
n += 1
return sa
-
+
assert self.meta_interp(f1, [5, 5]) == 50
self.check_loops(int_rshift=0, everywhere=True)
@@ -2175,7 +2201,7 @@
myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa)
if -5 <= a < 0: pass
if 0 < b <= 5: pass
- sa += (((((a << b) << b) << b) >> b) >> b) >> b
+ sa += (((((a << b) << b) << b) >> b) >> b) >> b
n += 1
return sa
@@ -2185,10 +2211,10 @@
myjitdriver.jit_merge_point(a=a, b=b, n=n, sa=sa)
if -promote(sys.maxint/2) < a < 0: pass
if 0 < b < 100: pass
- sa += (((((a << b) << b) << b) >> b) >> b) >> b
+ sa += (((((a << b) << b) << b) >> b) >> b) >> b
n += 1
return sa
-
+
assert self.meta_interp(f1, [-5, 5]) == -50
self.check_loops(int_rshift=0, everywhere=True)
@@ -2243,7 +2269,7 @@
def get_printable_location(i):
return str(i)
-
+
myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'],
get_printable_location=get_printable_location)
bytecode = "0j10jc20a3"
@@ -2352,7 +2378,7 @@
assert self.meta_interp(build, []) == 7
self.check_loops(getfield_gc_pure=0)
self.check_loops(getfield_gc_pure=2, everywhere=True)
-
+
def test_args_becomming_equal(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a', 'b'])
def f(n, a, b):
@@ -2707,7 +2733,7 @@
return sa
res = self.meta_interp(f, [])
assert res == f()
-
+
def test_frame_finished_during_continued_retrace(self):
class Base(object):
pass
@@ -2758,7 +2784,67 @@
assert res == -2
#self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx?
- def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self):
+ def test_retrace_ending_up_retracing_another_loop(self):
+
+ myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa'])
+ bytecode = "0+sI0+SI"
+ def f(n):
+ myjitdriver.set_param('threshold', 3)
+ myjitdriver.set_param('trace_eagerness', 1)
+ myjitdriver.set_param('retrace_limit', 5)
+ myjitdriver.set_param('function_threshold', -1)
+ pc = sa = i = 0
+ while pc < len(bytecode):
+ myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i)
+ n = hint(n, promote=True)
+ op = bytecode[pc]
+ if op == '0':
+ i = 0
+ elif op == '+':
+ i += 1
+ elif op == 's':
+ sa += i
+ elif op == 'S':
+ sa += 2
+ elif op == 'I':
+ if i < n:
+ pc -= 2
+ myjitdriver.can_enter_jit(pc=pc, n=n, sa=sa, i=i)
+ continue
+ pc += 1
+ return sa
+
+ def g(n1, n2):
+ for i in range(10):
+ f(n1)
+ for i in range(10):
+ f(n2)
+
+ nn = [10, 3]
+ assert self.meta_interp(g, nn) == g(*nn)
+
+ # The attempts of retracing first loop will end up retracing the
+ # second and thus fail 5 times, saturating the retrace_count. Instead a
+ # bridge back to the preamble of the first loop is produced. A guard in
+ # this bridge is later traced resulting in a retrace of the second loop.
+ # Thus we end up with:
+ # 1 preamble and 1 specialized version of first loop
+ # 1 preamble and 2 specialized version of second loop
+ self.check_tree_loop_count(2 + 3)
+
+ # FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times.
+
+ def g(n):
+ for i in range(n):
+ for j in range(10):
+ f(n-i)
+
+ res = self.meta_interp(g, [10])
+ assert res == g(10)
+ # 1 preamble and 6 speciealized versions of each loop
+ self.check_tree_loop_count(2*(1 + 6))
+
+ def test_continue_tracing_with_boxes_in_start_snapshot_replaced_by_optimizer(self):
myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'a', 'b'])
def f(n):
sa = a = 0
@@ -2798,6 +2884,11 @@
assert res == f(32)
self.check_loops(arraylen_gc=1)
+
+
+
+
+
class TestOOtype(BasicTests, OOJitMixin):
def test_oohash(self):
@@ -3066,6 +3157,59 @@
res = self.meta_interp(f, [32])
assert res == f(32)
self.check_loops(arraylen_gc=1, everywhere=True)
+
+ def test_release_gil_flush_heap_cache(self):
+ T = rffi.CArrayPtr(rffi.TIME_T)
+
+ external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True)
+ # Not a real lock, has all the same properties with respect to GIL
+ # release though, so good for this test.
+ class Lock(object):
+ @dont_look_inside
+ def acquire(self):
+ external(lltype.nullptr(T.TO))
+ @dont_look_inside
+ def release(self):
+ external(lltype.nullptr(T.TO))
+ class X(object):
+ def __init__(self, idx):
+ self.field = idx
+ @dont_look_inside
+ def get_obj(z):
+ return X(z)
+ myjitdriver = JitDriver(greens=[], reds=["n", "l", "z", "lock"])
+ def f(n, z):
+ lock = Lock()
+ l = 0
+ while n > 0:
+ myjitdriver.jit_merge_point(lock=lock, l=l, n=n, z=z)
+ x = get_obj(z)
+ l += x.field
+ lock.acquire()
+ # This must not reuse the previous one.
+ n -= x.field
+ lock.release()
+ return n
+ res = self.meta_interp(f, [10, 1])
+ self.check_loops(getfield_gc=2)
+ assert res == f(10, 1)
+
+ def test_jit_merge_point_with_raw_pointer(self):
+ driver = JitDriver(greens = [], reds = ['n', 'x'])
+
+ TP = lltype.Array(lltype.Signed, hints={'nolength': True})
+
+ def f(n):
+ x = lltype.malloc(TP, 10, flavor='raw')
+ x[0] = 1
+ while n > 0:
+ driver.jit_merge_point(n=n, x=x)
+ n -= x[0]
+ lltype.free(x, flavor='raw')
+ return n
+
+ self.meta_interp(f, [10], repeat=3)
+
class TestLLtype(BaseLLtypeTests, LLJitMixin):
pass
diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py
--- a/pypy/jit/metainterp/test/test_immutable.py
+++ b/pypy/jit/metainterp/test/test_immutable.py
@@ -1,5 +1,9 @@
+from pypy.rlib import jit
from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+ at jit.dont_look_inside
+def escape(x):
+ return x
class ImmutableFieldsTests:
@@ -11,7 +15,7 @@
self.x = x
def f(x):
- y = X(x)
+ y = escape(X(x))
return y.x + 5
res = self.interp_operations(f, [23])
assert res == 28
@@ -33,7 +37,7 @@
def f(x, y):
X(x) # force the field 'x' to be on class 'X'
- z = Y(x, y)
+ z = escape(Y(x, y))
return z.x + z.y + 5
res = self.interp_operations(f, [23, 11])
assert res == 39
@@ -42,7 +46,7 @@
def f(x, y):
# this time, the field 'x' only shows up on subclass 'Y'
- z = Y(x, y)
+ z = escape(Y(x, y))
return z.x + z.y + 5
res = self.interp_operations(f, [23, 11])
assert res == 39
@@ -58,7 +62,7 @@
def f(index):
l = [1, 2, 3, 4]
l[2] = 30
- a = X(l)
+ a = escape(X(l))
return a.y[index]
res = self.interp_operations(f, [2], listops=True)
assert res == 30
@@ -76,7 +80,7 @@
self.y = y
def f(x, index):
- y = X([x], x+1)
+ y = escape(X([x], x+1))
return y.lst[index] + y.y + 5
res = self.interp_operations(f, [23, 0], listops=True)
assert res == 23 + 24 + 5
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -0,0 +1,407 @@
+import py
+import sys
+from pypy.rlib import jit
+from pypy.jit.metainterp.test.support import LLJitMixin
+
+
+class TestLLtype(LLJitMixin):
+ def test_dont_record_repeated_guard_class(self):
+ class A:
+ pass
+ class B(A):
+ pass
+ @jit.dont_look_inside
+ def extern(n):
+ if n == -7:
+ return None
+ elif n:
+ return A()
+ else:
+ return B()
+ def fn(n):
+ obj = extern(n)
+ return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B)
+ res = self.interp_operations(fn, [0])
+ assert res == 4
+ self.check_operations_history(guard_class=1, guard_nonnull=1)
+ res = self.interp_operations(fn, [1])
+ assert not res
+
+ def test_dont_record_guard_class_after_new(self):
+ class A:
+ pass
+ class B(A):
+ pass
+ def fn(n):
+ if n == -7:
+ obj = None
+ elif n:
+ obj = A()
+ else:
+ obj = B()
+ return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, B)
+ res = self.interp_operations(fn, [0])
+ assert res == 4
+ self.check_operations_history(guard_class=0, guard_nonnull=0)
+ res = self.interp_operations(fn, [1])
+ assert not res
+
+ def test_guard_isnull_nullifies(self):
+ class A:
+ pass
+ a = A()
+ a.x = None
+ def fn(n):
+ if n == -7:
+ a.x = ""
+ obj = a.x
+ res = 0
+ if not obj:
+ res += 1
+ if obj:
+ res += 1
+ if obj is None:
+ res += 1
+ if obj is not None:
+ res += 1
+ return res
+ res = self.interp_operations(fn, [0])
+ assert res == 2
+ self.check_operations_history(guard_isnull=1)
+
+ def test_heap_caching_while_tracing(self):
+ class A:
+ pass
+ a1 = A()
+ a2 = A()
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a.x = n
+ return a.x
+ res = self.interp_operations(fn, [7])
+ assert res == 7
+ self.check_operations_history(getfield_gc=0)
+ res = self.interp_operations(fn, [-7])
+ assert res == -7
+ self.check_operations_history(getfield_gc=0)
+
+ def fn(n, ca, cb):
+ a1.x = n
+ a2.x = n
+ a = a1
+ if ca:
+ a = a2
+ b = a1
+ if cb:
+ b = a
+ return a.x + b.x
+ res = self.interp_operations(fn, [7, 0, 1])
+ assert res == 7 * 2
+ self.check_operations_history(getfield_gc=1)
+ res = self.interp_operations(fn, [-7, 1, 1])
+ assert res == -7 * 2
+ self.check_operations_history(getfield_gc=1)
+
+ def test_heap_caching_while_tracing_invalidation(self):
+ class A:
+ pass
+ a1 = A()
+ a2 = A()
+ @jit.dont_look_inside
+ def f(a):
+ a.x = 5
+ l = [1]
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a.x = n
+ x1 = a.x
+ f(a)
+ x2 = a.x
+ l[0] = x2
+ return a.x + x1 + x2
+ res = self.interp_operations(fn, [7])
+ assert res == 5 * 2 + 7
+ self.check_operations_history(getfield_gc=1)
+
+ def test_heap_caching_dont_store_same(self):
+ class A:
+ pass
+ a1 = A()
+ a2 = A()
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a.x = n
+ a.x = n
+ return a.x
+ res = self.interp_operations(fn, [7])
+ assert res == 7
+ self.check_operations_history(getfield_gc=0, setfield_gc=1)
+ res = self.interp_operations(fn, [-7])
+ assert res == -7
+ self.check_operations_history(getfield_gc=0)
+
+ def test_array_caching(self):
+ a1 = [0, 0]
+ a2 = [0, 0]
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a[0] = n
+ x1 = a[0]
+ a[n - n] = n + 1
+ return a[0] + x1
+ res = self.interp_operations(fn, [7])
+ assert res == 7 + 7 + 1
+ self.check_operations_history(getarrayitem_gc=1)
+ res = self.interp_operations(fn, [-7])
+ assert res == -7 - 7 + 1
+ self.check_operations_history(getarrayitem_gc=1)
+
+ def fn(n, ca, cb):
+ a1[0] = n
+ a2[0] = n
+ a = a1
+ if ca:
+ a = a2
+ b = a1
+ if cb:
+ b = a
+ return a[0] + b[0]
+ res = self.interp_operations(fn, [7, 0, 1])
+ assert res == 7 * 2
+ self.check_operations_history(getarrayitem_gc=1)
+ res = self.interp_operations(fn, [-7, 1, 1])
+ assert res == -7 * 2
+ self.check_operations_history(getarrayitem_gc=1)
+
+ def test_array_caching_while_tracing_invalidation(self):
+ a1 = [0, 0]
+ a2 = [0, 0]
+ @jit.dont_look_inside
+ def f(a):
+ a[0] = 5
+ class A: pass
+ l = A()
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a[0] = n
+ x1 = a[0]
+ f(a)
+ x2 = a[0]
+ l.x = x2
+ return a[0] + x1 + x2
+ res = self.interp_operations(fn, [7])
+ assert res == 5 * 2 + 7
+ self.check_operations_history(getarrayitem_gc=1)
+
+ def test_array_and_getfield_interaction(self):
+ class A: pass
+ a1 = A()
+ a2 = A()
+ a1.l = a2.l = [0, 0]
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a.l = [0, 0]
+ a.x = 0
+ a.l[a.x] = n
+ a.x += 1
+ a.l[a.x] = n + 1
+ x1 = a.l[a.x]
+ a.x -= 1
+ x2 = a.l[a.x]
+ return x1 + x2
+ res = self.interp_operations(fn, [7])
+ assert res == 7 * 2 + 1
+ self.check_operations_history(setarrayitem_gc=2, setfield_gc=3,
+ getarrayitem_gc=0, getfield_gc=1)
+
+ def test_promote_changes_heap_cache(self):
+ class A: pass
+ a1 = A()
+ a2 = A()
+ a1.l = a2.l = [0, 0]
+ a1.x = a2.x = 0
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a.l = [0, 0]
+ jit.promote(a.x)
+ a.l[a.x] = n
+ a.x += 1
+ a.l[a.x] = n + 1
+ x1 = a.l[a.x]
+ a.x -= 1
+ x2 = a.l[a.x]
+ return x1 + x2
+ res = self.interp_operations(fn, [7])
+ assert res == 7 * 2 + 1
+ self.check_operations_history(setarrayitem_gc=2, setfield_gc=2,
+ getarrayitem_gc=0, getfield_gc=2)
+
+ def test_list_caching(self):
+ a1 = [0, 0]
+ a2 = [0, 0]
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ if n < -1000:
+ a.append(5)
+ a[0] = n
+ x1 = a[0]
+ a[n - n] = n + 1
+ return a[0] + x1
+ res = self.interp_operations(fn, [7])
+ assert res == 7 + 7 + 1
+ self.check_operations_history(getarrayitem_gc=1,
+ getfield_gc=1)
+ res = self.interp_operations(fn, [-7])
+ assert res == -7 - 7 + 1
+ self.check_operations_history(getarrayitem_gc=1,
+ getfield_gc=1)
+
+ def fn(n, ca, cb):
+ a1[0] = n
+ a2[0] = n
+ a = a1
+ if ca:
+ a = a2
+ if n < -100:
+ a.append(5)
+ b = a1
+ if cb:
+ b = a
+ return a[0] + b[0]
+ res = self.interp_operations(fn, [7, 0, 1])
+ assert res == 7 * 2
+ self.check_operations_history(getarrayitem_gc=1,
+ getfield_gc=3)
+ res = self.interp_operations(fn, [-7, 1, 1])
+ assert res == -7 * 2
+ self.check_operations_history(getarrayitem_gc=1,
+ getfield_gc=3)
+
+ def test_list_caching_negative(self):
+ def fn(n):
+ a = [0] * n
+ if n > 1000:
+ a.append(0)
+ a[-1] = n
+ x1 = a[-1]
+ a[n - n - 1] = n + 1
+ return a[-1] + x1
+ res = self.interp_operations(fn, [7])
+ assert res == 7 + 7 + 1
+ self.check_operations_history(setarrayitem_gc=2,
+ setfield_gc=2)
+
+ def test_virtualizable_with_array_heap_cache(self):
+ myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'],
+ virtualizables = ['frame'])
+
+ class Frame(object):
+ _virtualizable2_ = ['l[*]', 's']
+
+ def __init__(self, a, s):
+ self = jit.hint(self, access_directly=True, fresh_virtualizable=True)
+ self.l = [0] * (4 + a)
+ self.s = s
+
+ def f(n, a, i):
+ frame = Frame(a, 0)
+ frame.l[0] = a
+ frame.l[1] = a + 1
+ frame.l[2] = a + 2
+ frame.l[3] = a + 3
+ if not i:
+ return frame.l[0] + len(frame.l)
+ x = 0
+ while n > 0:
+ myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i)
+ myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i)
+ frame.s = jit.promote(frame.s)
+ n -= 1
+ s = frame.s
+ assert s >= 0
+ x += frame.l[s]
+ frame.s += 1
+ s = frame.s
+ assert s >= 0
+ x += frame.l[s]
+ x += len(frame.l)
+ x += f(n, n, 0)
+ frame.s -= 1
+ return x
+
+ res = self.meta_interp(f, [10, 1, 1], listops=True)
+ assert res == f(10, 1, 1)
+ self.check_history(getarrayitem_gc=0, getfield_gc=0)
+
+ def test_heap_caching_pure(self):
+ class A(object):
+ pass
+ p1 = A()
+ p2 = A()
+ def fn(n):
+ if n >= 0:
+ a = (n, n + 1)
+ p = p1
+ else:
+ a = (n + 1, n)
+ p = p2
+ p.x = a
+
+ return p.x[0] + p.x[1]
+ res = self.interp_operations(fn, [7])
+ assert res == 7 + 7 + 1
+ self.check_operations_history(getfield_gc=0, getfield_gc_pure=0)
+ res = self.interp_operations(fn, [-7])
+ assert res == -7 - 7 + 1
+ self.check_operations_history(getfield_gc=0, getfield_gc_pure=0)
+
+ def test_heap_caching_and_elidable_function(self):
+ class A:
+ pass
+ class B: pass
+ a1 = A()
+ a1.y = 6
+ a2 = A()
+ a2.y = 13
+ @jit.elidable
+ def f(b):
+ return b + 1
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = A()
+ a.x = n
+ z = f(6)
+ return z + a.x
+ res = self.interp_operations(fn, [7])
+ assert res == 7 + 7
+ self.check_operations_history(getfield_gc=0)
+ res = self.interp_operations(fn, [-7])
+ assert res == -7 + 7
+ self.check_operations_history(getfield_gc=0)
+ return
diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py
--- a/pypy/jit/metainterp/test/test_virtualizable.py
+++ b/pypy/jit/metainterp/test/test_virtualizable.py
@@ -377,7 +377,7 @@
expected = f(20)
res = self.meta_interp(f, [20], enable_opts='')
assert res == expected
- self.check_loops(getfield_gc=3, setfield_gc=0,
+ self.check_loops(getfield_gc=1, setfield_gc=0,
arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1)
# ------------------------------
@@ -1133,6 +1133,7 @@
res = self.meta_interp(f, [10])
assert res == 55
self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True)
+ self.check_history(ptr_eq=2)
def test_virtual_child_frame_with_arrays(self):
myjitdriver = JitDriver(greens = [], reds = ['frame'],
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -10,6 +10,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import fatalerror
+from pypy.rlib.rstackovf import StackOverflow
from pypy.translator.simplify import get_functype
from pypy.translator.unsimplify import call_final_function
@@ -408,21 +409,28 @@
jd.warmstate = state
def crash_in_jit(e):
- if not we_are_translated():
- print "~~~ Crash in JIT!"
- print '~~~ %s: %s' % (e.__class__, e)
- if sys.stdout == sys.__stdout__:
- import pdb; pdb.post_mortem(sys.exc_info()[2])
- raise
- fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True)
+ try:
+ raise e
+ except JitException:
+ raise # go through
+ except MemoryError:
+ raise # go through
+ except StackOverflow:
+ raise # go through
+ except Exception, e:
+ if not we_are_translated():
+ print "~~~ Crash in JIT!"
+ print '~~~ %s: %s' % (e.__class__, e)
+ if sys.stdout == sys.__stdout__:
+ import pdb; pdb.post_mortem(sys.exc_info()[2])
+ raise
+ fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True)
crash_in_jit._dont_inline_ = True
if self.translator.rtyper.type_system.name == 'lltypesystem':
def maybe_enter_jit(*args):
try:
maybe_compile_and_run(state.increment_threshold, *args)
- except JitException:
- raise # go through
except Exception, e:
crash_in_jit(e)
maybe_enter_jit._always_inline_ = True
@@ -460,6 +468,9 @@
onlygreens=False)
jd._can_never_inline_ptr = self._make_hook_graph(jd,
annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool)
+ jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd,
+ annhelper, jd.jitdriver.should_unroll_one_iteration,
+ annmodel.s_Bool)
annhelper.finish()
def _make_hook_graph(self, jitdriver_sd, annhelper, func,
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -138,7 +138,10 @@
refvalue = cpu.ts.cast_to_ref(value)
cpu.set_future_value_ref(j, refvalue)
elif typecode == 'int':
- intvalue = lltype.cast_primitive(lltype.Signed, value)
+ if isinstance(lltype.typeOf(value), lltype.Ptr):
+ intvalue = llmemory.AddressAsInt(llmemory.cast_ptr_to_adr(value))
+ else:
+ intvalue = lltype.cast_primitive(lltype.Signed, value)
cpu.set_future_value_int(j, intvalue)
elif typecode == 'float':
if lltype.typeOf(value) is lltype.Float:
@@ -569,6 +572,19 @@
return can_inline_greenargs(*greenargs)
self.can_inline_greenargs = can_inline_greenargs
self.can_inline_callable = can_inline_callable
+
+ if jd._should_unroll_one_iteration_ptr is None:
+ def should_unroll_one_iteration(greenkey):
+ return False
+ else:
+ rtyper = self.warmrunnerdesc.rtyper
+ inline_ptr = jd._should_unroll_one_iteration_ptr
+ def should_unroll_one_iteration(greenkey):
+ greenargs = unwrap_greenkey(greenkey)
+ fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr)
+ return fn(*greenargs)
+ self.should_unroll_one_iteration = should_unroll_one_iteration
+
if hasattr(jd.jitdriver, 'on_compile'):
def on_compile(logger, token, operations, type, greenkey):
greenargs = unwrap_greenkey(greenkey)
diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py
--- a/pypy/jit/tool/oparser.py
+++ b/pypy/jit/tool/oparser.py
@@ -337,6 +337,11 @@
num += 1
return num, ops, last_offset
+ def postprocess(self, loop):
+ """ A hook that can be overloaded to do some postprocessing
+ """
+ return loop
+
def parse_offset(self, line):
if line.startswith('+'):
# it begins with an offset, like: "+10: i1 = int_add(...)"
diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py
--- a/pypy/module/__builtin__/abstractinst.py
+++ b/pypy/module/__builtin__/abstractinst.py
@@ -58,7 +58,10 @@
# -- case (anything, type)
try:
- w_result = space.isinstance(w_obj, w_klass_or_tuple, allow_override)
+ if allow_override:
+ w_result = space.isinstance_allow_override(w_obj, w_klass_or_tuple)
+ else:
+ w_result = space.isinstance(w_obj, w_klass_or_tuple)
except OperationError, e: # if w_klass_or_tuple was not a type, ignore it
if not e.match(space, space.w_TypeError):
raise # propagate other errors
@@ -72,8 +75,11 @@
w_pretendtype = space.getattr(w_obj, space.wrap('__class__'))
if space.is_w(w_pretendtype, space.type(w_obj)):
return False # common case: obj.__class__ is type(obj)
- w_result = space.issubtype(w_pretendtype, w_klass_or_tuple,
- allow_override)
+ if allow_override:
+ w_result = space.issubtype_allow_override(w_pretendtype,
+ w_klass_or_tuple)
+ else:
+ w_result = space.issubtype(w_pretendtype, w_klass_or_tuple)
except OperationError, e:
if e.async(space):
raise
@@ -134,7 +140,11 @@
# -- case (type, type)
try:
- w_result = space.issubtype(w_derived, w_klass_or_tuple, allow_override)
+ if allow_override:
+ w_result = space.issubtype_allow_override(w_derived,
+ w_klass_or_tuple)
+ else:
+ w_result = space.issubtype(w_derived, w_klass_or_tuple)
except OperationError, e: # if one of the args was not a type, ignore it
if not e.match(space, space.w_TypeError):
raise # propagate other errors
diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py
--- a/pypy/module/__builtin__/compiling.py
+++ b/pypy/module/__builtin__/compiling.py
@@ -5,7 +5,7 @@
from pypy.interpreter.pycode import PyCode
from pypy.interpreter.error import OperationError
from pypy.interpreter.astcompiler import consts, ast
-from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec
+from pypy.interpreter.gateway import unwrap_spec
@unwrap_spec(filename=str, mode=str, flags=int, dont_inherit=int)
def compile(space, w_source, filename, mode, flags=0, dont_inherit=0):
diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -1,12 +1,10 @@
-
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.function import StaticMethod, ClassMethod
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.objspace.descroperation import object_getattribute, object_setattr
-from pypy.interpreter.function import StaticMethod, ClassMethod
-from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \
- descr_set_dict, interp_attrproperty_w, generic_new_descr
+from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w,
+ generic_new_descr)
+from pypy.objspace.descroperation import object_getattribute
class W_Super(Wrappable):
def __init__(self, space, w_starttype, w_objtype, w_self):
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -4,13 +4,12 @@
"""
from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import NoneNotWrapped, applevel
+from pypy.interpreter.gateway import NoneNotWrapped
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.baseobjspace import Wrappable
from pypy.rlib.rarithmetic import r_uint, intmask
from pypy.rlib.objectmodel import specialize
-from inspect import getsource, getfile
from pypy.rlib.rbigint import rbigint
@@ -662,7 +661,6 @@
def descr_reduce(self):
from pypy.interpreter.mixedmodule import MixedModule
- from pypy.module._pickle_support import maker # helper fns
space = self.space
w_mod = space.getbuiltinmodule('_pickle_support')
mod = space.interp_w(MixedModule, w_mod)
diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py
--- a/pypy/module/__builtin__/interp_classobj.py
+++ b/pypy/module/__builtin__/interp_classobj.py
@@ -1,11 +1,9 @@
import new
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import NoneNotWrapped, applevel, interp2app
+from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef, make_weakref_descr
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.typedef import GetSetProperty, descr_get_dict
-from pypy.interpreter.typedef import descr_set_dict
-from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, descr_set_dict
from pypy.rlib.objectmodel import compute_identity_hash
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib import jit
@@ -420,7 +418,7 @@
if w_meth is not None:
space.call_function(w_meth, w_name)
else:
- if not self.deldictvalue(space, w_name):
+ if not self.deldictvalue(space, name):
raise operationerrfmt(
space.w_AttributeError,
"%s instance has no attribute '%s'",
diff --git a/pypy/module/__builtin__/interp_memoryview.py b/pypy/module/__builtin__/interp_memoryview.py
--- a/pypy/module/__builtin__/interp_memoryview.py
+++ b/pypy/module/__builtin__/interp_memoryview.py
@@ -2,7 +2,7 @@
Implementation of the 'buffer' and 'memoryview' types.
"""
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter import gateway, buffer
+from pypy.interpreter import buffer
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.error import OperationError
diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py
--- a/pypy/module/__builtin__/operation.py
+++ b/pypy/module/__builtin__/operation.py
@@ -4,12 +4,10 @@
from pypy.interpreter import gateway
from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.gateway import unwrap_spec
from pypy.rlib.runicode import UNICHR
from pypy.rlib.rfloat import isnan, isinf, round_double
from pypy.rlib import rfloat
-import math
import __builtin__
NoneNotWrapped = gateway.NoneNotWrapped
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -25,6 +25,7 @@
'debug_print_once' : 'interp_debug.debug_print_once',
'builtinify' : 'interp_magic.builtinify',
'lookup_special' : 'interp_magic.lookup_special',
+ 'do_what_I_mean' : 'interp_magic.do_what_I_mean',
}
submodules = {
diff --git a/pypy/module/__pypy__/interp_debug.py b/pypy/module/__pypy__/interp_debug.py
--- a/pypy/module/__pypy__/interp_debug.py
+++ b/pypy/module/__pypy__/interp_debug.py
@@ -1,5 +1,4 @@
-from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import unwrap_spec
from pypy.rlib import debug, jit
diff --git a/pypy/module/__pypy__/interp_identitydict.py b/pypy/module/__pypy__/interp_identitydict.py
--- a/pypy/module/__pypy__/interp_identitydict.py
+++ b/pypy/module/__pypy__/interp_identitydict.py
@@ -1,6 +1,6 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec
+from pypy.interpreter.gateway import interp2app
from pypy.interpreter.baseobjspace import Wrappable
class W_IdentityDict(Wrappable):
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -70,3 +70,6 @@
if w_descr is None:
return space.w_None
return space.get(w_descr, w_obj)
+
+def do_what_I_mean(space):
+ return space.wrap(42)
diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -49,3 +49,8 @@
class X:
pass
raises(TypeError, lookup_special, X(), "foo")
+
+ def test_do_what_I_mean(self):
+ from __pypy__ import do_what_I_mean
+ x = do_what_I_mean()
+ assert x == 42
diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py
--- a/pypy/module/_ast/test/test_ast.py
+++ b/pypy/module/_ast/test/test_ast.py
@@ -186,6 +186,11 @@
mod = self.get_ast("from __future__ import with_statement; import y; " \
"from __future__ import nested_scopes")
raises(SyntaxError, compile, mod, "<test>", "exec")
+ mod = self.get_ast("from __future__ import division\nx = 1/2")
+ co = compile(mod, "<test>", "exec")
+ ns = {}
+ exec co in ns
+ assert ns["x"] == .5
def test_field_attr_writable(self):
import _ast as ast
@@ -245,3 +250,38 @@
assert x.left == n1
assert x.op == addop
assert x.right == n3
+
+ def test_functiondef(self):
+ import _ast as ast
+ fAst = ast.FunctionDef(
+ name="foo",
+ args=ast.arguments(
+ args=[], vararg=None, kwarg=None, defaults=[],
+ kwonlyargs=[], kw_defaults=[]),
+ body=[], decorator_list=[], lineno=5, col_offset=0)
+ exprAst = ast.Interactive(body=[fAst])
+ compiled = compile(exprAst, "<foo>", "single")
+ #
+ d = {}
+ eval(compiled, d, d)
+ assert type(d['foo']) is type(lambda: 42)
+ assert d['foo']() is None
+
+ def test_missing_name(self):
+ import _ast as ast
+ n = ast.FunctionDef(name=None)
+ n.name = "foo"
+ n.name = "foo"
+ n.name = "foo"
+ assert n.name == "foo"
+
+ def test_issue793(self):
+ import _ast as ast
+ body = ast.Module([
+ ast.TryExcept([ast.Pass(lineno=2, col_offset=4)],
+ [ast.ExceptHandler(ast.Name('Exception', ast.Load(),
+ lineno=3, col_offset=0),
+ None, [], lineno=4, col_offset=0)],
+ [], lineno=1, col_offset=0)
+ ])
+ exec compile(body, '<string>', 'exec')
diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py
--- a/pypy/module/_codecs/interp_codecs.py
+++ b/pypy/module/_codecs/interp_codecs.py
@@ -1,6 +1,6 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec
-from pypy.rlib.rstring import StringBuilder, UnicodeBuilder
+from pypy.rlib.rstring import UnicodeBuilder
from pypy.rlib.objectmodel import we_are_translated
class CodecState(object):
diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py
--- a/pypy/module/_ffi/interp_ffi.py
+++ b/pypy/module/_ffi/interp_ffi.py
@@ -1,9 +1,8 @@
-import sys
-from pypy.interpreter.baseobjspace import Wrappable, Arguments
+from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.error import OperationError, wrap_oserror, \
operationerrfmt
-from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
from pypy.module._rawffi.structure import W_StructureInstance, W_Structure
#
from pypy.rpython.lltypesystem import lltype, rffi
@@ -16,7 +15,7 @@
class W_FFIType(Wrappable):
_immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to']
-
+
def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None):
self.name = name
self.ffitype = ffitype
@@ -83,7 +82,6 @@
def build_ffi_types():
- from pypy.rlib.clibffi import FFI_TYPE_P
types = [
# note: most of the type name directly come from the C equivalent,
# with the exception of bytes: in C, ubyte and char are equivalent,
@@ -149,13 +147,19 @@
raise OperationError(space.w_TypeError, space.wrap(msg))
return res
+def unwrap_truncate_int(TP, space, w_arg):
+ if space.is_true(space.isinstance(w_arg, space.w_int)):
+ return rffi.cast(TP, space.int_w(w_arg))
+ else:
+ return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask())
+unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)'
# ========================================================================
class W_FuncPtr(Wrappable):
_immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype']
-
+
def __init__(self, func, argtypes_w, w_restype):
self.func = func
self.argtypes_w = argtypes_w
@@ -181,15 +185,14 @@
# note that we must check for longlong first, because either
# is_signed or is_unsigned returns true anyway
assert libffi.IS_32_BIT
- kind = libffi.types.getkind(w_argtype.ffitype) # XXX: remove the kind
- self.arg_longlong(space, argchain, kind, w_arg)
+ self.arg_longlong(space, argchain, w_arg)
elif w_argtype.is_signed():
- argchain.arg(space.int_w(w_arg))
+ argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg))
elif w_argtype.is_pointer():
w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype)
argchain.arg(intmask(space.uint_w(w_arg)))
elif w_argtype.is_unsigned():
- argchain.arg(intmask(space.uint_w(w_arg)))
+ argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg))
elif w_argtype.is_char():
w_arg = space.ord(w_arg)
argchain.arg(space.int_w(w_arg))
@@ -202,7 +205,7 @@
argchain.arg_singlefloat(space.float_w(w_arg))
elif w_argtype.is_struct():
# arg_raw directly takes value to put inside ll_args
- w_arg = space.interp_w(W_StructureInstance, w_arg)
+ w_arg = space.interp_w(W_StructureInstance, w_arg)
ptrval = w_arg.ll_buffer
argchain.arg_raw(ptrval)
else:
@@ -220,15 +223,10 @@
return w_arg
@jit.dont_look_inside
- def arg_longlong(self, space, argchain, kind, w_arg):
+ def arg_longlong(self, space, argchain, w_arg):
bigarg = space.bigint_w(w_arg)
- if kind == 'I':
- llval = bigarg.tolonglong()
- elif kind == 'U':
- ullval = bigarg.toulonglong()
- llval = rffi.cast(rffi.LONGLONG, ullval)
- else:
- assert False
+ ullval = bigarg.ulonglongmask()
+ llval = rffi.cast(rffi.LONGLONG, ullval)
# this is a hack: we store the 64 bits of the long long into the
# 64 bits of a float (i.e., a C double)
floatval = libffi.longlong2float(llval)
@@ -404,7 +402,7 @@
except KeyError:
raise operationerrfmt(space.w_AttributeError,
"No symbol %s found in library %s", name, self.name)
-
+
return W_FuncPtr(func, argtypes_w, w_restype)
@unwrap_spec(name=str)
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
@@ -111,7 +111,6 @@
types.double)
assert pow(2, 3) == 8
-
def test_int_args(self):
"""
DLLEXPORT int sum_xy(int x, int y)
@@ -119,10 +118,12 @@
return x+y;
}
"""
+ import sys
from _ffi import CDLL, types
libfoo = CDLL(self.libfoo_name)
sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint)
assert sum_xy(30, 12) == 42
+ assert sum_xy(sys.maxint*2, 0) == -2
def test_void_result(self):
"""
@@ -247,6 +248,9 @@
types.ulong)
assert sum_xy(sys.maxint, 12) == sys.maxint+12
assert sum_xy(sys.maxint+1, 12) == sys.maxint+13
+ #
+ res = sum_xy(sys.maxint*2+3, 0)
+ assert res == 1
def test_unsigned_short_args(self):
"""
@@ -375,6 +379,9 @@
res = sum_xy(x, y)
expected = maxint64 + 3
assert res == expected
+ #
+ res = sum_xy(maxint64*2+3, 0)
+ assert res == 1
def test_byval_argument(self):
"""
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -43,11 +43,17 @@
# assume that the file and stream objects are only visible in the
# thread that runs __del__, so no race condition should be possible
self.clear_all_weakrefs()
+ if self.stream is not None:
+ self.enqueue_for_destruction(self.space, W_File.destructor,
+ 'close() method of ')
+
+ def destructor(self):
+ assert isinstance(self, W_File)
try:
self.direct_close()
except StreamErrors, e:
operr = wrap_streamerror(self.space, e, self.w_name)
- operr.write_unraisable(self.space, '__del__ of ', self)
+ raise operr
def fdopenstream(self, stream, fd, mode, w_name=None):
self.fd = fd
diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py
--- a/pypy/module/_file/interp_stream.py
+++ b/pypy/module/_file/interp_stream.py
@@ -3,12 +3,10 @@
from pypy.rlib.streamio import StreamErrors
from pypy.interpreter.error import OperationError, wrap_oserror2
-from pypy.interpreter.gateway import ObjSpace
-from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.gateway import interp2app
-import os
def wrap_streamerror(space, e, w_filename=None):
if isinstance(e, streamio.StreamError):
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -4,7 +4,6 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.buffer import RWBuffer
-from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.rstring import StringBuilder
from pypy.rlib.rarithmetic import r_longlong, intmask
from pypy.tool.sourcetools import func_renamer
diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py
--- a/pypy/module/_io/interp_fileio.py
+++ b/pypy/module/_io/interp_fileio.py
@@ -1,5 +1,4 @@
-from pypy.interpreter.typedef import (
- TypeDef, interp_attrproperty, interp_attrproperty_w, GetSetProperty)
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
from pypy.rlib.rarithmetic import r_longlong
diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py
--- a/pypy/module/_io/interp_io.py
+++ b/pypy/module/_io/interp_io.py
@@ -6,7 +6,6 @@
TypeDef, interp_attrproperty, generic_new_descr)
from pypy.module.exceptions.interp_exceptions import W_IOError
from pypy.module._io.interp_fileio import W_FileIO
-from pypy.module._io.interp_iobase import W_IOBase
from pypy.module._io.interp_textio import W_TextIOWrapper
from pypy.rpython.module.ll_os_stat import STAT_FIELD_TYPES
diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py
--- a/pypy/module/_io/interp_iobase.py
+++ b/pypy/module/_io/interp_iobase.py
@@ -57,6 +57,11 @@
def __del__(self):
self.clear_all_weakrefs()
+ self.enqueue_for_destruction(self.space, W_IOBase.destructor,
+ 'internal __del__ of ')
+
+ def destructor(self):
+ assert isinstance(self, W_IOBase)
space = self.space
w_closed = space.findattr(self, space.wrap('closed'))
try:
diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py
--- a/pypy/module/_io/interp_textio.py
+++ b/pypy/module/_io/interp_textio.py
@@ -4,7 +4,7 @@
generic_new_descr)
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import OperationError
from pypy.rlib.rarithmetic import intmask, r_ulonglong, r_uint
from pypy.rlib.rbigint import rbigint
from pypy.rlib.rstring import UnicodeBuilder
diff --git a/pypy/module/_locale/interp_locale.py b/pypy/module/_locale/interp_locale.py
--- a/pypy/module/_locale/interp_locale.py
+++ b/pypy/module/_locale/interp_locale.py
@@ -1,4 +1,3 @@
-from pypy.rpython.tool import rffi_platform as platform
from pypy.rlib import rposix
from pypy.rlib.rarithmetic import intmask
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -2,12 +2,10 @@
""" The ffi for rpython, need to be imported for side effects
"""
-import sys
from pypy.rpython.lltypesystem import rffi
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.tool import rffi_platform
from pypy.rpython.extfunc import register_external
-from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.module._minimal_curses import interp_curses
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -82,7 +80,7 @@
return res
finally:
rffi.free_charp(ll_cap)
-
+
register_external(interp_curses._curses_tigetstr, [str], str,
export_name='_curses.tigetstr', llimpl=tigetstr_llimpl)
diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py
--- a/pypy/module/_multibytecodec/c_codecs.py
+++ b/pypy/module/_multibytecodec/c_codecs.py
@@ -1,4 +1,4 @@
-import py, sys
+import py
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.tool.autopath import pypydir
@@ -55,10 +55,12 @@
"pypy_cjk_dec_init", "pypy_cjk_dec_free", "pypy_cjk_dec_chunk",
"pypy_cjk_dec_outbuf", "pypy_cjk_dec_outlen",
"pypy_cjk_dec_inbuf_remaining", "pypy_cjk_dec_inbuf_consumed",
+ "pypy_cjk_dec_replace_on_error",
"pypy_cjk_enc_init", "pypy_cjk_enc_free", "pypy_cjk_enc_chunk",
"pypy_cjk_enc_reset", "pypy_cjk_enc_outbuf", "pypy_cjk_enc_outlen",
"pypy_cjk_enc_inbuf_remaining", "pypy_cjk_enc_inbuf_consumed",
+ "pypy_cjk_enc_replace_on_error",
] + ["pypy_cjkcodec_%s" % codec for codec in codecs],
)
diff --git a/pypy/module/_multibytecodec/interp_multibytecodec.py b/pypy/module/_multibytecodec/interp_multibytecodec.py
--- a/pypy/module/_multibytecodec/interp_multibytecodec.py
+++ b/pypy/module/_multibytecodec/interp_multibytecodec.py
@@ -1,5 +1,5 @@
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec
+from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.error import OperationError
from pypy.module._multibytecodec import c_codecs
diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py
--- a/pypy/module/_multiprocessing/interp_connection.py
+++ b/pypy/module/_multiprocessing/interp_connection.py
@@ -4,7 +4,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.error import (
OperationError, wrap_oserror, operationerrfmt)
-from pypy.rpython.lltypesystem import rffi, lltype, llmemory
+from pypy.rpython.lltypesystem import rffi, lltype
from pypy.rlib.rarithmetic import intmask
from pypy.rlib import rpoll
import sys
diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py
--- a/pypy/module/_multiprocessing/interp_semaphore.py
+++ b/pypy/module/_multiprocessing/interp_semaphore.py
@@ -15,7 +15,6 @@
if sys.platform == 'win32':
from pypy.rlib import rwin32
- from pypy.interpreter.error import wrap_windowserror
from pypy.module._multiprocessing.interp_win32 import (
handle_w, _GetTickCount)
diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py
--- a/pypy/module/_pickle_support/maker.py
+++ b/pypy/module/_pickle_support/maker.py
@@ -1,4 +1,4 @@
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError
from pypy.interpreter.nestedscope import Cell
from pypy.interpreter.pycode import PyCode
from pypy.interpreter.function import Function, Method
@@ -8,7 +8,6 @@
from pypy.interpreter.generator import GeneratorIterator
from pypy.rlib.objectmodel import instantiate
from pypy.interpreter.gateway import unwrap_spec
-from pypy.objspace.std.dicttype import dictiter_typedef
from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject
@@ -79,7 +78,7 @@
try:
return gateway.BuiltinCode.find(identifier)
except KeyError:
- raise OperationError(space.w_RuntimeError,
+ raise OperationError(space.w_RuntimeError,
space.wrap("cannot unpickle builtin code: "+
identifier))
@@ -89,7 +88,7 @@
try:
return function.Function.find(identifier)
except KeyError:
- raise OperationError(space.w_RuntimeError,
+ raise OperationError(space.w_RuntimeError,
space.wrap("cannot unpickle builtin function: "+
identifier))
diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py
--- a/pypy/module/_rawffi/callback.py
+++ b/pypy/module/_rawffi/callback.py
@@ -2,10 +2,10 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.module._rawffi.array import get_elem, push_elem
+from pypy.module._rawffi.array import push_elem
from pypy.module._rawffi.structure import W_Structure
-from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \
- wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes
+from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp,
+ unwrap_value, unpack_argshapes)
from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL
from pypy.rlib.clibffi import ffi_type_void
from pypy.rlib import rweakref
diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -1,7 +1,6 @@
-import sys
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.error import OperationError, wrap_oserror, operationerrfmt
-from pypy.interpreter.gateway import interp2app, NoneNotWrapped, unwrap_spec
+from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.rlib.clibffi import *
@@ -15,7 +14,7 @@
from pypy.rlib import rwin32
from pypy.tool.sourcetools import func_with_new_name
-from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat
+from pypy.rlib.rarithmetic import intmask, r_uint
from pypy.module._rawffi.tracker import tracker
TYPEMAP = {
diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -1,9 +1,8 @@
-from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec
+from pypy.interpreter.gateway import unwrap_spec
from pypy.module._socket.interp_socket import converted_error, W_RSocket
from pypy.rlib import rsocket
from pypy.rlib.rsocket import SocketError
-from pypy.rlib.rarithmetic import r_uint
-from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import OperationError
def gethostname(space):
"""gethostname() -> string
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1,7 +1,7 @@
from __future__ import with_statement
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.interpreter.error import OperationError
-from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable
+from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.gateway import interp2app, unwrap_spec
@@ -11,7 +11,6 @@
from pypy.module._socket import interp_socket
-import sys
## user defined constants
X509_NAME_MAXLEN = 256
@@ -131,13 +130,13 @@
self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, flavor='raw')
self._issuer[0] = '\0'
self.shutdown_seen_zero = False
-
+
def server(self):
return self.space.wrap(rffi.charp2str(self._server))
-
+
def issuer(self):
return self.space.wrap(rffi.charp2str(self._issuer))
-
+
def __del__(self):
if self.peer_cert:
libssl_X509_free(self.peer_cert)
@@ -147,7 +146,7 @@
libssl_SSL_CTX_free(self.ctx)
lltype.free(self._server, flavor='raw')
lltype.free(self._issuer, flavor='raw')
-
+
@unwrap_spec(data='bufferstr')
def write(self, data):
"""write(s) -> len
@@ -230,10 +229,10 @@
raw_buf, gc_buf = rffi.alloc_buffer(num_bytes)
while True:
err = 0
-
+
count = libssl_SSL_read(self.ssl, raw_buf, num_bytes)
err = libssl_SSL_get_error(self.ssl, count)
-
+
if err == SSL_ERROR_WANT_READ:
sockstate = check_socket_and_wait_for_timeout(self.space,
self.w_socket, False)
@@ -245,17 +244,17 @@
return self.space.wrap("")
else:
sockstate = SOCKET_OPERATION_OK
-
+
if sockstate == SOCKET_HAS_TIMED_OUT:
raise ssl_error(self.space, "The read operation timed out")
elif sockstate == SOCKET_IS_NONBLOCKING:
break
-
+
if err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE:
continue
else:
break
-
+
if count <= 0:
raise _ssl_seterror(self.space, self, count)
@@ -351,7 +350,7 @@
self.shutdown_seen_zero = True
continue
- # Possibly retry shutdown until timeout or failure
+ # Possibly retry shutdown until timeout or failure
ssl_err = libssl_SSL_get_error(self.ssl, ret)
if ssl_err == SSL_ERROR_WANT_READ:
sockstate = check_socket_and_wait_for_timeout(
@@ -397,7 +396,7 @@
else:
w_proto = space.w_None
- bits = libssl_SSL_CIPHER_get_bits(current,
+ bits = libssl_SSL_CIPHER_get_bits(current,
lltype.nullptr(rffi.INTP.TO))
w_bits = space.newint(bits)
@@ -552,7 +551,7 @@
ext = libssl_X509_get_ext(certificate, i)
method = libssl_X509V3_EXT_get(ext)
if not method:
- raise ssl_error(space,
+ raise ssl_error(space,
"No method for internalizing subjectAltName!'")
with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr:
@@ -858,7 +857,7 @@
cert = libssl_BIO_new(libssl_BIO_s_file())
if not cert:
raise ssl_error(space, "Can't malloc memory to read file")
-
+
try:
if libssl_BIO_read_filename(cert, filename) <= 0:
raise ssl_error(space, "Can't open file")
@@ -873,7 +872,7 @@
libssl_X509_free(x)
finally:
libssl_BIO_free(cert)
-
+
# this function is needed to perform locking on shared data
# structures. (Note that OpenSSL uses a number of global data
# structures that will be implicitly shared whenever multiple threads
diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py
--- a/pypy/module/_stackless/interp_coroutine.py
+++ b/pypy/module/_stackless/interp_coroutine.py
@@ -15,13 +15,10 @@
experience to decide where to set the limits.
"""
-from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.argument import Arguments
from pypy.interpreter.typedef import GetSetProperty, TypeDef
-from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.function import StaticMethod
from pypy.module._stackless.stackless_flags import StacklessFlags
from pypy.module._stackless.rcoroutine import Coroutine, BaseCoState, AbstractThunk, CoroutineExit
@@ -38,7 +35,7 @@
self.costate = costate
if not space.is_true(space.callable(w_obj)):
raise operationerrfmt(
- space.w_TypeError,
+ space.w_TypeError,
"'%s' object is not callable",
space.type(w_obj).getname(space))
self.w_func = w_obj
@@ -65,7 +62,7 @@
# Should be moved to interp_stackless.py if it's ever implemented... Currently
# used by pypy/lib/stackless.py.
-W_TaskletExit = _new_exception('TaskletExit', W_SystemExit,
+W_TaskletExit = _new_exception('TaskletExit', W_SystemExit,
"""Tasklet killed manually.""")
class AppCoroutine(Coroutine): # XXX, StacklessFlags):
@@ -90,7 +87,7 @@
def _get_state(space):
return space.fromcache(AppCoState)
_get_state = staticmethod(_get_state)
-
+
def w_bind(self, w_func, __args__):
space = self.space
if self.frame is not None:
@@ -127,7 +124,7 @@
w_excvalue = operror.get_w_value(space)
w_exctraceback = operror.get_traceback()
w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback])
-
+
if w_exctype is self.costate.w_CoroutineExit:
self.coroutine_exit = True
else:
@@ -146,22 +143,22 @@
def w_kill(self):
self.kill()
-
+
def w_throw(self, w_type, w_value=None, w_traceback=None):
space = self.space
operror = OperationError(w_type, w_value)
operror.normalize_exception(space)
-
+
if not space.is_w(w_traceback, space.w_None):
from pypy.interpreter import pytraceback
tb = space.interpclass_w(w_traceback)
- if tb is None or not space.is_true(space.isinstance(tb,
+ if tb is None or not space.is_true(space.isinstance(tb,
space.gettypeobject(pytraceback.PyTraceback.typedef))):
raise OperationError(space.w_TypeError,
space.wrap("throw: arg 3 must be a traceback or None"))
operror.set_traceback(tb)
-
+
self._kill(operror)
def _userdel(self):
@@ -280,7 +277,7 @@
assert isinstance(w_klass, W_TypeObject)
old_flag = w_klass.flag_heaptype
w_klass.flag_heaptype = True
-
+
space.appexec([w_klass, space.wrap(funcname)], """
(klass, funcname):
func = getattr(klass, funcname)
@@ -332,23 +329,23 @@
# Exporting new exception to space
self.w_CoroutineExit = space.gettypefor(W_CoroutineExit)
space.setitem(
- space.exceptions_module.w_dict,
- space.new_interned_str('CoroutineExit'),
- self.w_CoroutineExit)
- space.setitem(space.builtin.w_dict,
- space.new_interned_str('CoroutineExit'),
+ space.exceptions_module.w_dict,
+ space.new_interned_str('CoroutineExit'),
self.w_CoroutineExit)
-
+ space.setitem(space.builtin.w_dict,
+ space.new_interned_str('CoroutineExit'),
+ self.w_CoroutineExit)
+
# Should be moved to interp_stackless.py if it's ever implemented...
self.w_TaskletExit = space.gettypefor(W_TaskletExit)
space.setitem(
- space.exceptions_module.w_dict,
- space.new_interned_str('TaskletExit'),
- self.w_TaskletExit)
- space.setitem(space.builtin.w_dict,
- space.new_interned_str('TaskletExit'),
- self.w_TaskletExit)
-
+ space.exceptions_module.w_dict,
+ space.new_interned_str('TaskletExit'),
+ self.w_TaskletExit)
+ space.setitem(space.builtin.w_dict,
+ space.new_interned_str('TaskletExit'),
+ self.w_TaskletExit)
+
def post_install(self):
self.current = self.main = AppCoroutine(self.space, state=self)
self.main.subctx.clear_framestack() # wack
@@ -378,7 +375,7 @@
instr = frame.last_instr
opcode = ord(code[instr])
map = pythonopcode.opmap
- call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'],
+ call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'],
map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']]
assert opcode in call_ops
instr += 1
diff --git a/pypy/module/_stackless/interp_stackless.py b/pypy/module/_stackless/interp_stackless.py
--- a/pypy/module/_stackless/interp_stackless.py
+++ b/pypy/module/_stackless/interp_stackless.py
@@ -1,9 +1,6 @@
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.typedef import GetSetProperty, TypeDef
-from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
+from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
-from pypy.rlib.rarithmetic import intmask
import os
diff --git a/pypy/module/_stackless/rclonable.py b/pypy/module/_stackless/rclonable.py
--- a/pypy/module/_stackless/rclonable.py
+++ b/pypy/module/_stackless/rclonable.py
@@ -1,7 +1,6 @@
from pypy.module._stackless.interp_coroutine import AbstractThunk, Coroutine
from pypy.rlib.rgc import gc_swap_pool, gc_clone
from pypy.rlib.objectmodel import we_are_translated
-from pypy.interpreter.error import OperationError
class InterpClonableMixin:
@@ -76,7 +75,7 @@
if not isinstance(current, InterpClonableCoroutine):
raise RuntimeError("fork() in a non-clonable coroutine")
thunk = ForkThunk(current)
- coro_fork = InterpClonableCoroutine()
+ coro_fork = InterpClonableCoroutine()
coro_fork.bind(thunk)
coro_fork.switch()
# we resume here twice. The following would need explanations about
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -1,16 +1,15 @@
import py
-from pypy.interpreter.argument import Arguments
from pypy.interpreter.baseobjspace import Wrappable, W_Root
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import interp2app, ObjSpace
-from pypy.interpreter.typedef import GetSetProperty, TypeDef
+from pypy.interpreter.typedef import TypeDef
from pypy.rlib import jit
import weakref
class WeakrefLifeline(W_Root):
def __init__(self, space):
- self.space = space # this is here for W_Root.clear_all_weakrefs()
+ self.space = space
self.refs_weak = []
self.cached_weakref_index = -1
self.cached_proxy_index = -1
@@ -23,8 +22,10 @@
"""
for i in range(len(self.refs_weak) - 1, -1, -1):
w_ref = self.refs_weak[i]()
- if w_ref is not None:
- self.space.user_del_action.register_weakref_callback(w_ref)
+ if w_ref is not None and w_ref.w_callable is not None:
+ w_ref.enqueue_for_destruction(self.space,
+ W_WeakrefBase.activate_callback,
+ 'weakref callback of ')
def clear_all_weakrefs(self):
"""Clear all weakrefs. This is called when an app-level object has
@@ -118,11 +119,8 @@
self.w_obj_weak = dead_ref
def activate_callback(w_self):
- if not w_self.w_callable is None:
- try:
- w_self.space.call_function(w_self.w_callable, w_self)
- except OperationError, e:
- e.write_unraisable(w_self.space, 'weakref callback ', w_self.w_callable)
+ assert isinstance(w_self, W_WeakrefBase)
+ w_self.space.call_function(w_self.w_callable, w_self)
def descr__repr__(self, space):
w_obj = self.dereference()
diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -1,6 +1,5 @@
from __future__ import with_statement
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.baseobjspace import ObjSpace, W_Root
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.error import OperationError, wrap_windowserror
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -1,18 +1,20 @@
from __future__ import with_statement
+from pypy.interpreter.buffer import RWBuffer
from pypy.interpreter.error import OperationError
-from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr
-from pypy.rpython.lltypesystem import lltype, rffi
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.rarithmetic import ovfcheck
-from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr
+from pypy.module._file.interp_file import W_File
+from pypy.objspace.std.model import W_Object
+from pypy.objspace.std.multimethod import FailedToImplement
from pypy.objspace.std.stdtypedef import SMM, StdTypeDef
from pypy.objspace.std.register_all import register_all
-from pypy.objspace.std.model import W_Object
-from pypy.module._file.interp_file import W_File
-from pypy.interpreter.buffer import RWBuffer
-from pypy.objspace.std.multimethod import FailedToImplement
+from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rpython.lltypesystem import lltype, rffi
+
+
+memcpy = rffi.llexternal("memcpy", [rffi.VOIDP, rffi.VOIDP, rffi.SIZE_T], lltype.Void)
@unwrap_spec(typecode=str)
def w_array(space, w_cls, typecode, __args__):
@@ -37,7 +39,7 @@
if len(__args__.arguments_w) > 0:
w_initializer = __args__.arguments_w[0]
if space.type(w_initializer) is space.w_str:
- a.fromstring(w_initializer)
+ a.fromstring(space.str_w(w_initializer))
elif space.type(w_initializer) is space.w_unicode:
a.fromsequence(w_initializer)
elif space.type(w_initializer) is space.w_list:
@@ -73,6 +75,7 @@
array_buffer_info = SMM('buffer_info', 1)
array_reduce = SMM('__reduce__', 1)
+array_copy = SMM('__copy__', 1)
array_byteswap = SMM('byteswap', 1)
@@ -96,7 +99,7 @@
itemsize = GetSetProperty(descr_itemsize),
typecode = GetSetProperty(descr_typecode),
__weakref__ = make_weakref_descr(W_ArrayBase),
- )
+)
W_ArrayBase.typedef.registermethods(globals())
@@ -159,8 +162,6 @@
self.data[index] = char
-
-
def make_array(mytype):
class W_Array(W_ArrayBase):
itemsize = mytype.bytes
@@ -268,12 +269,10 @@
raise
self.setlen(oldlen + i)
- def fromstring(self, w_s):
- space = self.space
- s = space.str_w(w_s)
+ def fromstring(self, s):
if len(s) % self.itemsize != 0:
msg = 'string length not a multiple of item size'
- raise OperationError(space.w_ValueError, space.wrap(msg))
+ raise OperationError(self.space.w_ValueError, self.space.wrap(msg))
oldlen = self.len
new = len(s) / mytype.bytes
self.setlen(oldlen + new)
@@ -311,6 +310,14 @@
def charbuf(self):
return rffi.cast(rffi.CCHARP, self.buffer)
+ def w_getitem(self, space, idx):
+ item = self.buffer[idx]
+ if mytype.typecode in 'bBhHil':
+ item = rffi.cast(lltype.Signed, item)
+ elif mytype.typecode == 'f':
+ item = float(item)
+ return space.wrap(item)
+
# Basic get/set/append/extend methods
def len__Array(space, self):
@@ -319,12 +326,7 @@
def getitem__Array_ANY(space, self, w_idx):
idx, stop, step = space.decode_index(w_idx, self.len)
assert step == 0
- item = self.buffer[idx]
- if mytype.typecode in 'bBhHil':
- item = rffi.cast(lltype.Signed, item)
- elif mytype.typecode == 'f':
- item = float(item)
- return self.space.wrap(item)
+ return self.w_getitem(space, idx)
def getitem__Array_Slice(space, self, w_slice):
start, stop, step, size = space.decode_index4(w_slice, self.len)
@@ -387,7 +389,7 @@
def array_count__Array_ANY(space, self, w_val):
cnt = 0
for i in range(self.len):
- w_item = getitem__Array_ANY(space, self, space.wrap(i))
+ w_item = self.w_getitem(space, i)
if space.is_true(space.eq(w_item, w_val)):
cnt += 1
return space.wrap(cnt)
@@ -395,7 +397,7 @@
def array_index__Array_ANY(space, self, w_val):
cnt = 0
for i in range(self.len):
- w_item = getitem__Array_ANY(space, self, space.wrap(i))
+ w_item = self.w_getitem(space, i)
if space.is_true(space.eq(w_item, w_val)):
return space.wrap(i)
msg = 'array.index(x): x not in list'
@@ -413,7 +415,7 @@
if i < 0 or i >= self.len:
msg = 'pop index out of range'
raise OperationError(space.w_IndexError, space.wrap(msg))
- w_val = getitem__Array_ANY(space, self, space.wrap(i))
+ w_val = self.w_getitem(space, i)
while i < self.len - 1:
self.buffer[i] = self.buffer[i + 1]
i += 1
@@ -515,14 +517,14 @@
def array_tolist__Array(space, self):
w_l = space.newlist([])
for i in range(self.len):
- w_l.append(getitem__Array_ANY(space, self, space.wrap(i)))
+ w_l.append(self.w_getitem(space, i))
return w_l
def array_fromlist__Array_List(space, self, w_lst):
self.fromlist(w_lst)
def array_fromstring__Array_ANY(space, self, w_s):
- self.fromstring(w_s)
+ self.fromstring(space.str_w(w_s))
def array_tostring__Array(space, self):
cbuf = self.charbuf()
@@ -569,10 +571,7 @@
self.fromsequence(w_ustr)
def array_tounicode__Array(space, self):
- u = u""
- for i in range(self.len):
- u += self.buffer[i]
- return space.wrap(u)
+ return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len))
else:
def array_fromunicode__Array_Unicode(space, self, w_ustr):
@@ -615,6 +614,16 @@
dct = space.w_None
return space.newtuple([space.type(self), space.newtuple(args), dct])
+ def array_copy__Array(space, self):
+ w_a = mytype.w_class(self.space)
+ w_a.setlen(self.len)
+ memcpy(
+ rffi.cast(rffi.VOIDP, w_a.buffer),
+ rffi.cast(rffi.VOIDP, self.buffer),
+ self.len * mytype.bytes
+ )
+ return w_a
+
def array_byteswap__Array(space, self):
if mytype.bytes not in [1, 2, 4, 8]:
msg = "byteswap not supported for this array"
diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py
--- a/pypy/module/binascii/interp_crc32.py
+++ b/pypy/module/binascii/interp_crc32.py
@@ -61,7 +61,7 @@
crc_32_tab = map(r_uint, crc_32_tab)
- at unwrap_spec(data='bufferstr', oldcrc='c_int')
+ at unwrap_spec(data='bufferstr', oldcrc='truncatedint')
def crc32(space, data, oldcrc=0):
"Compute the CRC-32 incrementally."
diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py
--- a/pypy/module/binascii/test/test_binascii.py
+++ b/pypy/module/binascii/test/test_binascii.py
@@ -374,6 +374,8 @@
('x', 10000, -1855256896),
('y', 10000, -429115818),
('z', 10000, 2137352172),
+ ('foo', 99999999999999999999999999, -1932704816),
+ ('bar', -99999999999999999999999999, 2000545409),
]:
assert self.binascii.crc32(input, initial) == expected
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
@@ -4,9 +4,8 @@
from pypy.rpython.lltypesystem import lltype
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.interpreter.typedef import interp_attrproperty
-from pypy.interpreter.gateway import NoneNotWrapped, interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.rlib.streamio import Stream
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.translator.platform import platform as compiler
@@ -67,7 +66,7 @@
'BZ_OUTBUFF_FULL', 'BZ_CONFIG_ERROR']
for name in constant_names:
setattr(CConfig, name, platform.DefinedConstantInteger(name))
-
+
class cConfig(object):
pass
for k, v in platform.configure(CConfig).items():
@@ -100,7 +99,7 @@
SMALLCHUNK = 8192
else:
SMALLCHUNK = BUFSIZ
-
+
if rffi.sizeof(rffi.INT) > 4:
BIGCHUNK = 512 * 32
else:
@@ -505,7 +504,7 @@
self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True)
self.running = False
self._init_bz2comp(compresslevel)
-
+
def _init_bz2comp(self, compresslevel):
if compresslevel < 1 or compresslevel > 9:
raise OperationError(self.space.w_ValueError,
@@ -514,13 +513,13 @@
bzerror = intmask(BZ2_bzCompressInit(self.bzs, compresslevel, 0, 0))
if bzerror != BZ_OK:
_catch_bz2_error(self.space, bzerror)
-
+
self.running = True
-
+
def __del__(self):
BZ2_bzCompressEnd(self.bzs)
lltype.free(self.bzs, flavor='raw')
-
+
@unwrap_spec(data='bufferstr')
def compress(self, data):
"""compress(data) -> string
@@ -529,12 +528,12 @@
compressed data whenever possible. When you've finished providing data
to compress, call the flush() method to finish the compression process,
and return what is left in the internal buffers."""
-
+
datasize = len(data)
-
+
if datasize == 0:
return self.space.wrap("")
-
+
if not self.running:
raise OperationError(self.space.w_ValueError,
self.space.wrap("this object was already flushed"))
@@ -562,7 +561,7 @@
res = out.make_result_string()
return self.space.wrap(res)
-
+
def flush(self):
if not self.running:
raise OperationError(self.space.w_ValueError,
@@ -576,7 +575,7 @@
break
elif bzerror != BZ_FINISH_OK:
_catch_bz2_error(self.space, bzerror)
-
+
if rffi.getintfield(self.bzs, 'c_avail_out') == 0:
out.prepare_next_chunk()
@@ -603,23 +602,23 @@
Create a new decompressor object. This object may be used to decompress
data sequentially. If you want to decompress data in one shot, use the
decompress() function instead."""
-
+
def __init__(self, space):
self.space = space
self.bzs = lltype.malloc(bz_stream.TO, flavor='raw', zero=True)
self.running = False
self.unused_data = ""
-
+
self._init_bz2decomp()
-
+
def _init_bz2decomp(self):
bzerror = BZ2_bzDecompressInit(self.bzs, 0, 0)
if bzerror != BZ_OK:
_catch_bz2_error(self.space, bzerror)
-
+
self.running = True
-
+
def __del__(self):
BZ2_bzDecompressEnd(self.bzs)
lltype.free(self.bzs, flavor='raw')
@@ -687,7 +686,7 @@
Compress data in one shot. If you want to compress data sequentially,
use an instance of BZ2Compressor instead. The compresslevel parameter, if
given, must be a number between 1 and 9."""
-
+
if compresslevel < 1 or compresslevel > 9:
raise OperationError(space.w_ValueError,
space.wrap("compresslevel must be between 1 and 9"))
@@ -731,7 +730,7 @@
Decompress data in one shot. If you want to decompress data sequentially,
use an instance of BZ2Decompressor instead."""
-
+
in_bufsize = len(data)
if in_bufsize == 0:
return space.wrap("")
diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py
--- a/pypy/module/bz2/test/test_bz2_file.py
+++ b/pypy/module/bz2/test/test_bz2_file.py
@@ -133,6 +133,7 @@
bz2f.seek(0)
assert bz2f.tell() == 0
+ del bz2f # delete from this frame, which is captured in the traceback
def test_open_close_del(self):
from bz2 import BZ2File
@@ -246,11 +247,18 @@
assert text_read == self.TEXT
bz2f.close()
+ def test_silently_closes(self):
+ from bz2 import BZ2File
+ self.create_broken_temp_file()
+ BZ2File(self.temppath)
+ # check that no C-level malloc is left behind
+
def test_read_broken_file(self):
from bz2 import BZ2File
self.create_broken_temp_file()
bz2f = BZ2File(self.temppath)
raises(EOFError, bz2f.read)
+ del bz2f # delete from this frame, which is captured in the traceback
def test_subsequent_read_broken_file(self):
from bz2 import BZ2File
@@ -264,6 +272,7 @@
raise Exception("should generate EOFError earlier")
except EOFError:
pass
+ del bz2f # delete from this frame, which is captured in the traceback
def test_read_chunk10(self):
from bz2 import BZ2File
@@ -416,6 +425,7 @@
bz2f.close()
bz2f = BZ2File(self.temppath, 'r')
assert bz2f.read() == self.random_data
+ del bz2f # delete from this frame, which is captured in the traceback
def test_context_manager(self):
from bz2 import BZ2File
diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py
--- a/pypy/module/cStringIO/interp_stringio.py
+++ b/pypy/module/cStringIO/interp_stringio.py
@@ -1,4 +1,3 @@
-import sys
from pypy.interpreter.error import OperationError
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.typedef import TypeDef, GetSetProperty
diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py
--- a/pypy/module/cmath/interp_cmath.py
+++ b/pypy/module/cmath/interp_cmath.py
@@ -5,7 +5,7 @@
from pypy.tool.sourcetools import func_with_new_name
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import NoneNotWrapped
-from pypy.module.cmath import Module, names_and_docstrings
+from pypy.module.cmath import names_and_docstrings
from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN
from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG
from pypy.module.cmath.constant import M_LN2, M_LN10
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -337,7 +337,7 @@
'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', 'init_capsule',
'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
-
+
'PyOS_getsig', 'PyOS_setsig',
'PyStructSequence_InitType', 'PyStructSequence_New',
@@ -745,7 +745,7 @@
ctypes.c_void_p)
setup_va_functions(eci)
-
+
setup_init_functions(eci)
return modulename.new(ext='')
@@ -771,7 +771,7 @@
export_symbols[:] = renamed_symbols
else:
export_symbols[:] = [sym.replace("#", "") for sym in export_symbols]
-
+
# Generate defines
for macro_name, size in [
("SIZEOF_LONG_LONG", rffi.LONGLONG),
@@ -784,7 +784,7 @@
]:
pypy_macros.append("#define %s %s" % (macro_name, rffi.sizeof(size)))
pypy_macros.append('')
-
+
pypy_macros_h = udir.join('pypy_macros.h')
pypy_macros_h.write('\n'.join(pypy_macros))
@@ -852,7 +852,7 @@
# Sometimes the library is wrapped into another DLL, ensure that
# the correct bootstrap code is installed
kwds["link_extra"] = ["msvcrt.lib"]
- elif sys.platform == 'linux2':
+ elif sys.platform.startswith('linux'):
compile_extra.append("-Werror=implicit-function-declaration")
export_symbols_eci.append('pypyAPI')
else:
@@ -1007,7 +1007,7 @@
FT = lltype.typeOf(func).TO
return make_generic_cpy_call(FT, False, False)(space, func, *args)
- at specialize.ll()
+ at specialize.ll()
def generic_cpy_call_expect_null(space, func, *args):
FT = lltype.typeOf(func).TO
return make_generic_cpy_call(FT, True, True)(space, func, *args)
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -1,8 +1,7 @@
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef
-from pypy.module.cpyext.api import (
- cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields)
+from pypy.module.cpyext.pyobject import PyObject, make_ref
+from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct,
+ PyObjectFields)
from pypy.module.cpyext.import_ import PyImport_Import
from pypy.module.cpyext.typeobject import PyTypeObjectPtr
from pypy.interpreter.error import OperationError
diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py
--- a/pypy/module/cpyext/complexobject.py
+++ b/pypy/module/cpyext/complexobject.py
@@ -1,7 +1,6 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.module.cpyext.api import (
cpython_api, cpython_struct, PyObject, build_type_checkers)
-from pypy.module.cpyext.pyerrors import PyErr_BadArgument
from pypy.module.cpyext.floatobject import PyFloat_AsDouble
from pypy.objspace.std.complexobject import W_ComplexObject
from pypy.interpreter.error import OperationError
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
#define PY_VERSION "2.7.1"
/* PyPy version as a string */
-#define PYPY_VERSION "1.5.0"
+#define PYPY_VERSION "1.6.0"
/* Subversion Revision number of this file (not of the repository) */
#define PY_PATCHLEVEL_REVISION "$Revision: 77872 $"
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -22,7 +22,7 @@
def PySequence_Check(space, w_obj):
"""Return 1 if the object provides sequence protocol, and 0 otherwise.
This function always succeeds."""
- return int(space.findattr(w_obj, space.wrap("__getitem__")) is not None)
+ return int(space.issequence_w(w_obj))
@cpython_api([PyObject], Py_ssize_t, error=-1)
def PySequence_Size(space, w_obj):
diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py
--- a/pypy/module/cpyext/stringobject.py
+++ b/pypy/module/cpyext/stringobject.py
@@ -268,3 +268,7 @@
if errors:
w_errors = space.wrap(rffi.charp2str(errors))
return space.call_method(w_str, 'encode', w_encoding, w_errors)
+
+ at cpython_api([PyObject, PyObject], PyObject)
+def _PyString_Join(space, w_sep, w_seq):
+ return space.call_method(w_sep, 'join', w_seq)
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -188,7 +188,7 @@
kwds["compile_extra"] = ["/we4013"]
else:
kwds["link_files"] = [str(api_library + '.so')]
- if sys.platform == 'linux2':
+ if sys.platform.startswith('linux'):
kwds["compile_extra"]=["-Werror=implicit-function-declaration"]
return compile_module(self.space, name, **kwds)
diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py
--- a/pypy/module/cpyext/test/test_stringobject.py
+++ b/pypy/module/cpyext/test/test_stringobject.py
@@ -287,3 +287,9 @@
def test_eq(self, space, api):
assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello"))
assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world"))
+
+ def test_join(self, space, api):
+ w_sep = space.wrap('<sep>')
+ w_seq = space.wrap(['a', 'b'])
+ w_joined = api._PyString_Join(w_sep, w_seq)
+ assert space.unwrap(w_joined) == 'a<sep>b'
diff --git a/pypy/module/crypt/interp_crypt.py b/pypy/module/crypt/interp_crypt.py
--- a/pypy/module/crypt/interp_crypt.py
+++ b/pypy/module/crypt/interp_crypt.py
@@ -1,6 +1,5 @@
-from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec
-from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.lltypesystem import rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo
import sys
@@ -22,4 +21,4 @@
if not res:
return space.w_None
str_res = rffi.charp2str(res)
- return space.wrap(str_res)
+ return space.wrap(str_res)
diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -73,9 +73,8 @@
"""
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w,\
- GetSetProperty, interp_attrproperty, descr_get_dict, descr_set_dict,\
- descr_del_dict
+from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict,
+ descr_set_dict, descr_del_dict)
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.error import OperationError
from pypy.rlib import rwin32
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
@@ -11,9 +11,8 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.eval import Code
from pypy.interpreter.pycode import PyCode
-from pypy.rlib import streamio, jit, rposix
+from pypy.rlib import streamio, jit
from pypy.rlib.streamio import StreamErrors
-from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import we_are_translated, specialize
from pypy.module.sys.version import PYPY_VERSION
@@ -86,7 +85,7 @@
return SEARCH_ERROR, None, None
-if sys.platform == 'linux2' or 'freebsd' in sys.platform:
+if sys.platform.startswith('linux') or 'freebsd' in sys.platform:
def case_ok(filename):
return True
else:
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
@@ -3,9 +3,9 @@
from pypy.rlib import streamio
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.module import Module
-from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec
+from pypy.interpreter.gateway import unwrap_spec
from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror
-import struct
+
def get_suffixes(space):
w = space.wrap
diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py
--- a/pypy/module/itertools/interp_itertools.py
+++ b/pypy/module/itertools/interp_itertools.py
@@ -2,7 +2,6 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.typedef import TypeDef, make_weakref_descr
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.rlib.rarithmetic import ovfcheck
class W_Count(Wrappable):
@@ -87,7 +86,7 @@
def __init__(self, space, w_obj, w_times):
self.space = space
self.w_obj = w_obj
-
+
if space.is_w(w_times, space.w_None):
self.counting = False
self.count = 0
@@ -181,7 +180,7 @@
long as the predicate is true.
Equivalent to :
-
+
def takewhile(predicate, iterable):
for x in iterable:
if predicate(x):
@@ -316,7 +315,7 @@
None, return the items that are false.
Equivalent to :
-
+
def ifilterfalse(predicate, iterable):
if predicate is None:
predicate = bool
@@ -380,16 +379,23 @@
self.start = -1
else: # all following calls
consume = self.step
+ if consume > 1:
+ self._ignore_items(consume-1)
if self.stop >= 0:
if self.stop < consume:
+ self.stop = 0 # reset the state so that a following next_w()
+ self.step = 1 # has no effect any more
raise OperationError(self.space.w_StopIteration,
self.space.w_None)
self.stop -= consume
+ return self.space.next(self.iterable)
+
+ def _ignore_items(self, num):
while True:
- w_obj = self.space.next(self.iterable)
- consume -= 1
- if consume <= 0:
- return w_obj
+ self.space.next(self.iterable)
+ num -= 1
+ if num <= 0:
+ break
def W_ISlice___new__(space, w_subtype, w_iterable, w_startstop, args_w):
r = space.allocate_instance(W_ISlice, w_subtype)
@@ -570,7 +576,7 @@
yield tuple(args)
else:
yield function(*args)
-
+
""")
@@ -728,9 +734,9 @@
__doc__ = """Make an iterator returning elements from the iterable and
saving a copy of each. When the iterable is exhausted, return
elements from the saved copy. Repeats indefinitely.
-
+
Equivalent to :
-
+
def cycle(iterable):
saved = []
for element in iterable:
@@ -738,7 +744,7 @@
saved.append(element)
while saved:
for element in saved:
- yield element
+ yield element
""")
class W_StarMap(Wrappable):
@@ -778,7 +784,7 @@
def starmap(function, iterable):
iterable = iter(iterable)
while True:
- yield function(*iterable.next())
+ yield function(*iterable.next())
""")
@@ -788,15 +794,15 @@
Note : once tee() has made a split, the original iterable
should not be used anywhere else; otherwise, the iterable could get
advanced without the tee objects being informed.
-
+
Note : this member of the toolkit may require significant auxiliary
storage (depending on how much temporary data needs to be stored).
In general, if one iterator is going to use most or all of the
data before the other iterator, it is faster to use list() instead
of tee()
-
+
Equivalent to :
-
+
def tee(iterable, n=2):
def gen(next, data={}, cnt=[0]):
for i in count():
@@ -888,7 +894,7 @@
self.exhausted = False
self.started = False
# new_group - new group not started yet, next should not skip any items
- self.new_group = True
+ self.new_group = True
self.w_lookahead = self.space.w_None
self.w_key = self.space.w_None
diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -227,6 +227,45 @@
assert list(itertools.islice(xrange(10), None,None)) == range(10)
assert list(itertools.islice(xrange(10), None,None,None)) == range(10)
+ def test_islice_dropitems_exact(self):
+ import itertools
+
+ it = iter("abcdefghij")
+ itertools.islice(it, 2, 2) # doesn't eagerly drop anything
+ assert it.next() == "a"
+ itertools.islice(it, 3, 8, 2) # doesn't eagerly drop anything
+ assert it.next() == "b"
+ assert it.next() == "c"
+
+ it = iter("abcdefghij")
+ x = next(itertools.islice(it, 2, 3), None) # drops 2 items
+ assert x == "c"
+ assert it.next() == "d"
+
+ it = iter("abcdefghij")
+ x = next(itertools.islice(it, 3, 8, 2), None) # drops 3 items
+ assert x == "d"
+ assert it.next() == "e"
+
+ it = iter("abcdefghij")
+ x = next(itertools.islice(it, None, 8), None) # drops 0 items
+ assert x == "a"
+ assert it.next() == "b"
+
+ it = iter("abcdefghij")
+ x = next(itertools.islice(it, 3, 2), None) # drops 3 items
+ assert x is None
+ assert it.next() == "d"
+
+ it = iter("abcdefghij")
+ islc = itertools.islice(it, 3, 7, 2)
+ assert islc.next() == "d" # drops 0, 1, 2, returns item #3
+ assert it.next() == "e"
+ assert islc.next() == "g" # drops the 4th and return item #5
+ assert it.next() == "h"
+ raises(StopIteration, islc.next) # drops the 6th and raise
+ assert it.next() == "j"
+
def test_islice_overflow(self):
import itertools
import sys
diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py
--- a/pypy/module/marshal/interp_marshal.py
+++ b/pypy/module/marshal/interp_marshal.py
@@ -1,10 +1,8 @@
-from pypy.interpreter.baseobjspace import ObjSpace
from pypy.interpreter.error import OperationError
from pypy.rlib.rarithmetic import intmask
from pypy.rlib import rstackovf
from pypy.module._file.interp_file import W_File
-from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror
-import sys
+
Py_MARSHAL_VERSION = 2
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
@@ -10,18 +10,27 @@
'zeros': 'interp_numarray.zeros',
'empty': 'interp_numarray.zeros',
'ones': 'interp_numarray.ones',
+ 'fromstring': 'interp_support.fromstring',
# ufuncs
'abs': 'interp_ufuncs.absolute',
'absolute': 'interp_ufuncs.absolute',
+ 'add': 'interp_ufuncs.add',
'copysign': 'interp_ufuncs.copysign',
+ 'divide': 'interp_ufuncs.divide',
'exp': 'interp_ufuncs.exp',
+ 'fabs': 'interp_ufuncs.fabs',
'floor': 'interp_ufuncs.floor',
'maximum': 'interp_ufuncs.maximum',
'minimum': 'interp_ufuncs.minimum',
+ 'multiply': 'interp_ufuncs.multiply',
'negative': 'interp_ufuncs.negative',
'reciprocal': 'interp_ufuncs.reciprocal',
'sign': 'interp_ufuncs.sign',
+ 'subtract': 'interp_ufuncs.subtract',
+ 'sin': 'interp_ufuncs.sin',
+ 'cos': 'interp_ufuncs.cos',
+ 'tan': 'interp_ufuncs.tan',
}
appleveldefs = {
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -3,7 +3,7 @@
It should not be imported by the module itself
"""
-from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray
+from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray
class BogusBytecode(Exception):
pass
@@ -18,6 +18,14 @@
def wrap(self, x):
return x
+ def issequence_w(self, w_obj):
+ # Completley wrong in the general case, but good enough for this.
+ return isinstance(w_obj, BaseArray)
+
+ def float_w(self, w_obj):
+ assert isinstance(w_obj, float)
+ return w_obj
+
def numpy_compile(bytecode, array_size):
space = TrivialSpace()
stack = []
@@ -40,6 +48,11 @@
elif b == '/':
right = stack.pop()
stack.append(stack.pop().descr_div(space, right))
+ elif b == '%':
+ right = stack.pop()
+ stack.append(stack.pop().descr_mod(space, right))
+ elif b == '|':
+ stack.append(stack.pop().descr_abs(space))
else:
print "Unknown opcode: %s" % b
raise BogusBytecode()
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
@@ -1,43 +1,36 @@
-from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
-from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.module.micronumpy.interp_support import Signature
+from pypy.module.micronumpy import interp_ufuncs
+from pypy.objspace.std.floatobject import float2string as float2string_orig
from pypy.rlib import jit
+from pypy.rlib.rfloat import DTSF_STR_PRECISION
from pypy.rpython.lltypesystem import lltype
from pypy.tool.sourcetools import func_with_new_name
-
-
-def dummy1(v):
- assert isinstance(v, float)
- return v
-
-def dummy2(v):
- assert isinstance(v, float)
- return v
+import math
TP = lltype.Array(lltype.Float, hints={'nolength': True})
numpy_driver = jit.JitDriver(greens = ['signature'],
reds = ['result_size', 'i', 'self', 'result'])
-
-class Signature(object):
- def __init__(self):
- self.transitions = {}
-
- def transition(self, target):
- if target in self.transitions:
- return self.transitions[target]
- self.transitions[target] = new = Signature()
- return new
+all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self'])
+any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self'])
+slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
+slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
def add(v1, v2):
return v1 + v2
-def sub(v1, v2):
- return v1 - v2
def mul(v1, v2):
return v1 * v2
-def div(v1, v2):
- return v1 / v2
+def maximum(v1, v2):
+ return max(v1, v2)
+def minimum(v1, v2):
+ return min(v1, v2)
+
+def float2string(x):
+ return float2string_orig(x, 'g', DTSF_STR_PRECISION)
class BaseArray(Wrappable):
def __init__(self):
@@ -52,44 +45,185 @@
arr.force_if_needed()
del self.invalidates[:]
- def _binop_impl(function):
- signature = Signature()
+ def _unaryop_impl(w_ufunc):
+ def impl(self, space):
+ return w_ufunc(space, self)
+ return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__)
+
+ descr_pos = _unaryop_impl(interp_ufuncs.positive)
+ descr_neg = _unaryop_impl(interp_ufuncs.negative)
+ descr_abs = _unaryop_impl(interp_ufuncs.absolute)
+
+ def _binop_impl(w_ufunc):
def impl(self, space, w_other):
- new_sig = self.signature.transition(signature)
- if isinstance(w_other, BaseArray):
- res = Call2(
- function,
- self,
- w_other,
- new_sig.transition(w_other.signature)
- )
- w_other.invalidates.append(res)
- else:
- w_other = FloatWrapper(space.float_w(w_other))
- res = Call2(
- function,
- self,
- w_other,
- new_sig.transition(w_other.signature)
- )
- self.invalidates.append(res)
- return space.wrap(res)
- return func_with_new_name(impl, "binop_%s_impl" % function.__name__)
+ return w_ufunc(space, self, w_other)
+ return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__)
- descr_add = _binop_impl(add)
- descr_sub = _binop_impl(sub)
- descr_mul = _binop_impl(mul)
- descr_div = _binop_impl(div)
+ descr_add = _binop_impl(interp_ufuncs.add)
+ descr_sub = _binop_impl(interp_ufuncs.subtract)
+ descr_mul = _binop_impl(interp_ufuncs.multiply)
+ descr_div = _binop_impl(interp_ufuncs.divide)
+ descr_pow = _binop_impl(interp_ufuncs.power)
+ descr_mod = _binop_impl(interp_ufuncs.mod)
+
+ def _binop_right_impl(w_ufunc):
+ def impl(self, space, w_other):
+ w_other = FloatWrapper(space.float_w(w_other))
+ return w_ufunc(space, w_other, self)
+ return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__)
+
+ descr_radd = _binop_right_impl(interp_ufuncs.add)
+ descr_rsub = _binop_right_impl(interp_ufuncs.subtract)
+ descr_rmul = _binop_right_impl(interp_ufuncs.multiply)
+ descr_rdiv = _binop_right_impl(interp_ufuncs.divide)
+ descr_rpow = _binop_right_impl(interp_ufuncs.power)
+ descr_rmod = _binop_right_impl(interp_ufuncs.mod)
+
+ def _reduce_sum_prod_impl(function, init):
+ reduce_driver = jit.JitDriver(greens=['signature'],
+ reds = ['i', 'size', 'self', 'result'])
+
+ def loop(self, result, size):
+ i = 0
+ while i < size:
+ reduce_driver.jit_merge_point(signature=self.signature,
+ self=self, size=size, i=i,
+ result=result)
+ result = function(result, self.eval(i))
+ i += 1
+ return result
+
+ def impl(self, space):
+ return space.wrap(loop(self, init, self.find_size()))
+ return func_with_new_name(impl, "reduce_%s_impl" % function.__name__)
+
+ def _reduce_max_min_impl(function):
+ reduce_driver = jit.JitDriver(greens=['signature'],
+ reds = ['i', 'size', 'self', 'result'])
+ def loop(self, result, size):
+ i = 1
+ while i < size:
+ reduce_driver.jit_merge_point(signature=self.signature,
+ self=self, size=size, i=i,
+ result=result)
+ result = function(result, self.eval(i))
+ i += 1
+ return result
+
+ def impl(self, space):
+ size = self.find_size()
+ if size == 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("Can't call %s on zero-size arrays" \
+ % function.__name__))
+ return space.wrap(loop(self, self.eval(0), size))
+ return func_with_new_name(impl, "reduce_%s_impl" % function.__name__)
+
+ def _reduce_argmax_argmin_impl(function):
+ reduce_driver = jit.JitDriver(greens=['signature'],
+ reds = ['i', 'size', 'result', 'self', 'cur_best'])
+ def loop(self, size):
+ result = 0
+ cur_best = self.eval(0)
+ i = 1
+ while i < size:
+ reduce_driver.jit_merge_point(signature=self.signature,
+ self=self, size=size, i=i,
+ result=result, cur_best=cur_best)
+ new_best = function(cur_best, self.eval(i))
+ if new_best != cur_best:
+ result = i
+ cur_best = new_best
+ i += 1
+ return result
+ def impl(self, space):
+ size = self.find_size()
+ if size == 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("Can't call %s on zero-size arrays" \
+ % function.__name__))
+ return space.wrap(loop(self, size))
+ return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__)
+
+ def _all(self):
+ size = self.find_size()
+ i = 0
+ while i < size:
+ all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i)
+ if not self.eval(i):
+ return False
+ i += 1
+ return True
+ def descr_all(self, space):
+ return space.wrap(self._all())
+
+ def _any(self):
+ size = self.find_size()
+ i = 0
+ while i < size:
+ any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i)
+ if self.eval(i):
+ return True
+ i += 1
+ return False
+ def descr_any(self, space):
+ return space.wrap(self._any())
+
+ descr_sum = _reduce_sum_prod_impl(add, 0.0)
+ descr_prod = _reduce_sum_prod_impl(mul, 1.0)
+ descr_max = _reduce_max_min_impl(maximum)
+ descr_min = _reduce_max_min_impl(minimum)
+ descr_argmax = _reduce_argmax_argmin_impl(maximum)
+ descr_argmin = _reduce_argmax_argmin_impl(minimum)
+
+ def descr_dot(self, space, w_other):
+ if isinstance(w_other, BaseArray):
+ w_res = self.descr_mul(space, w_other)
+ assert isinstance(w_res, BaseArray)
+ return w_res.descr_sum(space)
+ else:
+ return self.descr_mul(space, w_other)
+
+ def _getnums(self, comma):
+ if self.find_size() > 1000:
+ nums = [
+ float2string(self.getitem(index))
+ for index in range(3)
+ ]
+ nums.append("..." + "," * comma)
+ nums.extend([
+ float2string(self.getitem(index))
+ for index in range(self.find_size() - 3, self.find_size())
+ ])
+ else:
+ nums = [
+ float2string(self.getitem(index))
+ for index in range(self.find_size())
+ ]
+ return nums
def get_concrete(self):
raise NotImplementedError
+ def descr_copy(self, space):
+ return new_numarray(space, self)
+
def descr_get_shape(self, space):
return space.newtuple([self.descr_len(space)])
def descr_len(self, space):
return self.get_concrete().descr_len(space)
+ def descr_repr(self, space):
+ # Simple implementation so that we can see the array. Needs work.
+ concrete = self.get_concrete()
+ return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])")
+
+ def descr_str(self, space):
+ # Simple implementation so that we can see the array. Needs work.
+ concrete = self.get_concrete()
+ return space.wrap("[" + " ".join(concrete._getnums(True)) + "]")
+
def descr_getitem(self, space, w_idx):
# TODO: indexing by tuples
start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size())
@@ -101,19 +235,61 @@
res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature))
return space.wrap(res)
- @unwrap_spec(item=int, value=float)
- def descr_setitem(self, space, item, value):
+ def descr_setitem(self, space, w_idx, w_value):
+ # TODO: indexing by tuples and lists
self.invalidated()
- return self.get_concrete().descr_setitem(space, item, value)
+ start, stop, step, slice_length = space.decode_index4(w_idx,
+ self.find_size())
+ if step == 0:
+ # Single index
+ self.get_concrete().setitem(start, space.float_w(w_value))
+ else:
+ concrete = self.get_concrete()
+ if isinstance(w_value, BaseArray):
+ # for now we just copy if setting part of an array from
+ # part of itself. can be improved.
+ if (concrete.get_root_storage() ==
+ w_value.get_concrete().get_root_storage()):
+ w_value = new_numarray(space, w_value)
+ else:
+ w_value = convert_to_array(space, w_value)
+ concrete.setslice(space, start, stop, step,
+ slice_length, w_value)
def descr_mean(self, space):
- s = 0
- concrete = self.get_concrete()
- size = concrete.find_size()
- for i in xrange(size):
- s += concrete.getitem(i)
- return space.wrap(s / size)
+ return space.wrap(space.float_w(self.descr_sum(space))/self.find_size())
+ def _sliceloop1(self, start, stop, step, source, dest):
+ i = start
+ j = 0
+ while i < stop:
+ slice_driver1.jit_merge_point(signature=source.signature,
+ step=step, stop=stop, i=i, j=j, source=source,
+ dest=dest)
+ dest.storage[i] = source.eval(j)
+ j += 1
+ i += step
+
+ def _sliceloop2(self, start, stop, step, source, dest):
+ i = start
+ j = 0
+ while i > stop:
+ slice_driver2.jit_merge_point(signature=source.signature,
+ step=step, stop=stop, i=i, j=j, source=source,
+ dest=dest)
+ dest.storage[i] = source.eval(j)
+ j += 1
+ i += step
+
+def convert_to_array (space, w_obj):
+ if isinstance(w_obj, BaseArray):
+ return w_obj
+ elif space.issequence_w(w_obj):
+ # Convert to array.
+ return new_numarray(space, w_obj)
+ else:
+ # If it's a scalar
+ return FloatWrapper(space.float_w(w_obj))
class FloatWrapper(BaseArray):
"""
@@ -249,8 +425,8 @@
return self.parent.getitem(self.calc_index(item))
@unwrap_spec(item=int, value=float)
- def descr_setitem(self, space, item, value):
- return self.parent.descr_setitem(space, self.calc_index(item), value)
+ def setitem(self, item, value):
+ return self.parent.setitem(self.calc_index(item), value)
def descr_len(self, space):
return space.wrap(self.find_size())
@@ -264,14 +440,34 @@
def __init__(self, start, stop, step, slice_length, parent, signature):
ViewArray.__init__(self, parent, signature)
- self.start = start
- self.stop = stop
- self.step = step
+ if isinstance(parent, SingleDimSlice):
+ self.start = parent.calc_index(start)
+ self.stop = parent.calc_index(stop)
+ self.step = parent.step * step
+ self.parent = parent.parent
+ else:
+ self.start = start
+ self.stop = stop
+ self.step = step
+ self.parent = parent
self.size = slice_length
+ def get_root_storage(self):
+ return self.parent.storage
+
def find_size(self):
return self.size
+ def setslice(self, space, start, stop, step, slice_length, arr):
+ start = self.calc_index(start)
+ if stop != -1:
+ stop = self.calc_index(stop)
+ step = self.step * step
+ if step > 0:
+ self._sliceloop1(start, stop, step, arr, self.parent)
+ else:
+ self._sliceloop2(start, stop, step, arr, self.parent)
+
def calc_index(self, item):
return (self.start + item * self.step)
@@ -289,46 +485,45 @@
def get_concrete(self):
return self
+ def get_root_storage(self):
+ return self.storage
+
def find_size(self):
return self.size
def eval(self, i):
return self.storage[i]
- def getindex(self, space, item):
- if item >= self.size:
- raise operationerrfmt(space.w_IndexError,
- '%d above array size', item)
- if item < 0:
- item += self.size
- if item < 0:
- raise operationerrfmt(space.w_IndexError,
- '%d below zero', item)
- return item
-
def descr_len(self, space):
return space.wrap(self.size)
def getitem(self, item):
return self.storage[item]
- @unwrap_spec(item=int, value=float)
- def descr_setitem(self, space, item, value):
- item = self.getindex(space, item)
+ def setitem(self, item, value):
self.invalidated()
self.storage[item] = value
+ def setslice(self, space, start, stop, step, slice_length, arr):
+ if step > 0:
+ self._sliceloop1(start, stop, step, arr, self)
+ else:
+ self._sliceloop2(start, stop, step, arr, self)
+
def __del__(self):
lltype.free(self.storage, flavor='raw')
-def descr_new_numarray(space, w_type, w_size_or_iterable):
+def new_numarray(space, w_size_or_iterable):
l = space.listview(w_size_or_iterable)
arr = SingleDimArray(len(l))
i = 0
for w_elem in l:
arr.storage[i] = space.float_w(space.float(w_elem))
i += 1
- return space.wrap(arr)
+ return arr
+
+def descr_new_numarray(space, w_type, w_size_or_iterable):
+ return space.wrap(new_numarray(space, w_size_or_iterable))
@unwrap_spec(size=int)
def zeros(space, size):
@@ -345,16 +540,39 @@
'numarray',
__new__ = interp2app(descr_new_numarray),
+ copy = interp2app(BaseArray.descr_copy),
shape = GetSetProperty(BaseArray.descr_get_shape),
__len__ = interp2app(BaseArray.descr_len),
__getitem__ = interp2app(BaseArray.descr_getitem),
__setitem__ = interp2app(BaseArray.descr_setitem),
+ __pos__ = interp2app(BaseArray.descr_pos),
+ __neg__ = interp2app(BaseArray.descr_neg),
+ __abs__ = interp2app(BaseArray.descr_abs),
__add__ = interp2app(BaseArray.descr_add),
__sub__ = interp2app(BaseArray.descr_sub),
__mul__ = interp2app(BaseArray.descr_mul),
__div__ = interp2app(BaseArray.descr_div),
+ __pow__ = interp2app(BaseArray.descr_pow),
+ __mod__ = interp2app(BaseArray.descr_mod),
+ __radd__ = interp2app(BaseArray.descr_radd),
+ __rsub__ = interp2app(BaseArray.descr_rsub),
+ __rmul__ = interp2app(BaseArray.descr_rmul),
+ __rdiv__ = interp2app(BaseArray.descr_rdiv),
+ __rpow__ = interp2app(BaseArray.descr_rpow),
+ __rmod__ = interp2app(BaseArray.descr_rmod),
+ __repr__ = interp2app(BaseArray.descr_repr),
+ __str__ = interp2app(BaseArray.descr_str),
mean = interp2app(BaseArray.descr_mean),
+ sum = interp2app(BaseArray.descr_sum),
+ prod = interp2app(BaseArray.descr_prod),
+ max = interp2app(BaseArray.descr_max),
+ min = interp2app(BaseArray.descr_min),
+ argmax = interp2app(BaseArray.descr_argmax),
+ argmin = interp2app(BaseArray.descr_argmin),
+ all = interp2app(BaseArray.descr_all),
+ any = interp2app(BaseArray.descr_any),
+ dot = interp2app(BaseArray.descr_dot),
)
diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_support.py
@@ -0,0 +1,42 @@
+from pypy.rlib.rstruct.runpack import runpack
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import unwrap_spec
+
+
+FLOAT_SIZE = rffi.sizeof(lltype.Float)
+
+ at unwrap_spec(s=str)
+def fromstring(space, s):
+ from pypy.module.micronumpy.interp_numarray import SingleDimArray
+ length = len(s)
+
+ if length % FLOAT_SIZE == 0:
+ number = length/FLOAT_SIZE
+ else:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "string length %d not divisable by %d" % (length, FLOAT_SIZE)))
+
+ a = SingleDimArray(number)
+
+ start = 0
+ end = FLOAT_SIZE
+ i = 0
+ while i < number:
+ part = s[start:end]
+ a.storage[i] = runpack('d', part)
+ i += 1
+ start += FLOAT_SIZE
+ end += FLOAT_SIZE
+
+ return space.wrap(a)
+
+class Signature(object):
+ def __init__(self):
+ self.transitions = {}
+
+ def transition(self, target):
+ if target in self.transitions:
+ return self.transitions[target]
+ self.transitions[target] = new = Signature()
+ return new
\ No newline at end of file
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
@@ -1,31 +1,36 @@
import math
-from pypy.interpreter.gateway import unwrap_spec
-from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature
+from pypy.module.micronumpy.interp_support import Signature
from pypy.rlib import rfloat
from pypy.tool.sourcetools import func_with_new_name
-
def ufunc(func):
signature = Signature()
def impl(space, w_obj):
- if isinstance(w_obj, BaseArray):
- w_res = Call1(func, w_obj, w_obj.signature.transition(signature))
- w_obj.invalidates.append(w_res)
+ from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array
+ if space.issequence_w(w_obj):
+ w_obj_arr = convert_to_array(space, w_obj)
+ w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature))
+ w_obj_arr.invalidates.append(w_res)
return w_res
- return space.wrap(func(space.float_w(w_obj)))
+ else:
+ return space.wrap(func(space.float_w(w_obj)))
return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
def ufunc2(func):
signature = Signature()
def impl(space, w_lhs, w_rhs):
- if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray):
- new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature)
- w_res = Call2(func, w_lhs, w_rhs, new_sig)
- w_lhs.invalidates.append(w_res)
- w_rhs.invalidates.append(w_res)
+ from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array
+ if space.issequence_w(w_lhs) or space.issequence_w(w_rhs):
+ w_lhs_arr = convert_to_array(space, w_lhs)
+ w_rhs_arr = convert_to_array(space, w_rhs)
+ new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature)
+ w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig)
+ w_lhs_arr.invalidates.append(w_res)
+ w_rhs_arr.invalidates.append(w_res)
return w_res
- return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
+ else:
+ return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
@ufunc
@@ -33,9 +38,17 @@
return abs(value)
@ufunc2
+def add(lvalue, rvalue):
+ return lvalue + rvalue
+
+ at ufunc2
def copysign(lvalue, rvalue):
return rfloat.copysign(lvalue, rvalue)
+ at ufunc2
+def divide(lvalue, rvalue):
+ return lvalue / rvalue
+
@ufunc
def exp(value):
try:
@@ -43,6 +56,10 @@
except OverflowError:
return rfloat.INFINITY
+ at ufunc
+def fabs(value):
+ return math.fabs(value)
+
@ufunc2
def maximum(lvalue, rvalue):
return max(lvalue, rvalue)
@@ -51,6 +68,15 @@
def minimum(lvalue, rvalue):
return min(lvalue, rvalue)
+ at ufunc2
+def multiply(lvalue, rvalue):
+ return lvalue * rvalue
+
+# Used by numarray for __pos__. Not visible from numpy application space.
+ at ufunc
+def positive(value):
+ return value
+
@ufunc
def negative(value):
return -value
@@ -61,6 +87,10 @@
return rfloat.copysign(rfloat.INFINITY, value)
return 1.0 / value
+ at ufunc2
+def subtract(lvalue, rvalue):
+ return lvalue - rvalue
+
@ufunc
def floor(value):
return math.floor(value)
@@ -70,3 +100,23 @@
if value == 0.0:
return 0.0
return rfloat.copysign(1.0, value)
+
+ at ufunc
+def sin(value):
+ return math.sin(value)
+
+ at ufunc
+def cos(value):
+ return math.cos(value)
+
+ at ufunc
+def tan(value):
+ return math.tan(value)
+
+ at ufunc2
+def power(lvalue, rvalue):
+ return math.pow(lvalue, rvalue)
+
+ at ufunc2
+def mod(lvalue, rvalue):
+ return math.fmod(lvalue, rvalue)
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,12 +1,10 @@
from pypy.conftest import gettestobjspace
from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper
-
class BaseNumpyAppTest(object):
def setup_class(cls):
cls.space = gettestobjspace(usemodules=('micronumpy',))
-
class TestSignature(object):
def test_binop_signature(self, space):
ar = SingleDimArray(10)
@@ -26,4 +24,4 @@
v3 = ar.descr_add(space, v1)
v4 = ar.descr_add(space, v2)
- assert v3.signature is v4.signature
\ No newline at end of file
+ assert v3.signature is v4.signature
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,6 +1,7 @@
import py
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+from pypy.conftest import gettestobjspace
class AppTestNumArray(BaseNumpyAppTest):
@@ -37,11 +38,50 @@
a[2] = 4
assert a[2] == 4
+ def test_copy(self):
+ from numpy import array
+ a = array(range(5))
+ b = a.copy()
+ for i in xrange(5):
+ assert b[i] == a[i]
+
def test_iterator_init(self):
from numpy import array
a = array(range(5))
assert a[3] == 3
+ def test_repr(self):
+ from numpy import array, zeros
+ a = array(range(5))
+ assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])"
+ a = zeros(1001)
+ assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+
+ def test_repr_slice(self):
+ from numpy import array, zeros
+ a = array(range(5))
+ b = a[1::2]
+ assert repr(b) == "array([1.0, 3.0])"
+ a = zeros(2002)
+ b = a[::2]
+ assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+
+ def test_str(self):
+ from numpy import array, zeros
+ a = array(range(5))
+ assert str(a) == "[0.0 1.0 2.0 3.0 4.0]"
+ a = zeros(1001)
+ assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
+
+ def test_str_slice(self):
+ from numpy import array, zeros
+ a = array(range(5))
+ b = a[1::2]
+ assert str(b) == "[1.0 3.0]"
+ a = zeros(2002)
+ b = a[::2]
+ assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
+
def test_getitem(self):
from numpy import array
a = array(range(5))
@@ -59,6 +99,51 @@
raises(IndexError, "a[5] = 0.0")
raises(IndexError, "a[-6] = 3.0")
+ def test_setslice_array(self):
+ from numpy import array
+ a = array(range(5))
+ b = array(range(2))
+ a[1:4:2] = b
+ assert a[1] == 0.
+ assert a[3] == 1.
+ b[::-1] = b
+ assert b[0] == 1.
+ assert b[1] == 0.
+
+ def test_setslice_of_slice_array(self):
+ from numpy import array, zeros
+ a = zeros(5)
+ a[::2] = array([9., 10., 11.])
+ assert a[0] == 9.
+ assert a[2] == 10.
+ assert a[4] == 11.
+ a[1:4:2][::-1] = array([1., 2.])
+ assert a[0] == 9.
+ assert a[1] == 2.
+ assert a[2] == 10.
+ assert a[3] == 1.
+ assert a[4] == 11.
+ a = zeros(10)
+ a[::2][::-1][::2] = array(range(1,4))
+ assert a[8] == 1.
+ assert a[4] == 2.
+ assert a[0] == 3.
+
+ def test_setslice_list(self):
+ from numpy import array
+ a = array(range(5))
+ b = [0., 1.]
+ a[1:4:2] = b
+ assert a[1] == 0.
+ assert a[3] == 1.
+
+ def test_setslice_constant(self):
+ from numpy import array
+ a = array(range(5))
+ a[1:4:2] = 0.
+ assert a[1] == 0.
+ assert a[3] == 0.
+
def test_len(self):
from numpy import array
a = array(range(5))
@@ -96,6 +181,21 @@
for i in range(5):
assert b[i] == i + 5
+ def test_radd(self):
+ from numpy import array
+ r = 3 + array(range(3))
+ for i in range(3):
+ assert r[i] == i + 3
+
+ def test_add_list(self):
+ from numpy import array
+ a = array(range(5))
+ b = list(reversed(range(5)))
+ c = a + b
+ assert isinstance(c, array)
+ for i in range(5):
+ assert c[i] == 4
+
def test_subtract(self):
from numpy import array
a = array(range(5))
@@ -154,6 +254,72 @@
for i in range(5):
assert b[i] == i / 5.0
+ def test_pow(self):
+ from numpy import array
+ a = array(range(5))
+ b = a ** a
+ for i in range(5):
+ print b[i], i**i
+ assert b[i] == i**i
+
+ def test_pow_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array([2, 2, 2, 2, 2])
+ c = a ** b
+ for i in range(5):
+ assert c[i] == i ** 2
+
+ def test_pow_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a ** 2
+ for i in range(5):
+ assert b[i] == i ** 2
+
+ def test_mod(self):
+ from numpy import array
+ a = array(range(1,6))
+ b = a % a
+ for i in range(5):
+ assert b[i] == 0
+
+ def test_mod_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array([2, 2, 2, 2, 2])
+ c = a % b
+ for i in range(5):
+ assert c[i] == i % 2
+
+ def test_mod_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a % 2
+ for i in range(5):
+ assert b[i] == i % 2
+
+ def test_pos(self):
+ from numpy import array
+ a = array([1.,-2.,3.,-4.,-5.])
+ b = +a
+ for i in range(5):
+ assert b[i] == a[i]
+
+ def test_neg(self):
+ from numpy import array
+ a = array([1.,-2.,3.,-4.,-5.])
+ b = -a
+ for i in range(5):
+ assert b[i] == -a[i]
+
+ def test_abs(self):
+ from numpy import array
+ a = array([1.,-2.,3.,-4.,-5.])
+ b = abs(a)
+ for i in range(5):
+ assert b[i] == abs(a[i])
+
def test_auto_force(self):
from numpy import array
a = array(range(5))
@@ -210,7 +376,97 @@
assert d[1] == 12
def test_mean(self):
- from numpy import array, mean
+ from numpy import array
a = array(range(5))
assert a.mean() == 2.0
- assert a[:4].mean() == 1.5
\ No newline at end of file
+ assert a[:4].mean() == 1.5
+
+ def test_sum(self):
+ from numpy import array
+ a = array(range(5))
+ assert a.sum() == 10.0
+ assert a[:4].sum() == 6.0
+
+ def test_prod(self):
+ from numpy import array
+ a = array(range(1,6))
+ assert a.prod() == 120.0
+ assert a[:4].prod() == 24.0
+
+ def test_max(self):
+ from numpy import array
+ a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
+ assert a.max() == 5.7
+ b = array([])
+ raises(ValueError, "b.max()")
+
+ def test_max_add(self):
+ from numpy import array
+ a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
+ assert (a+a).max() == 11.4
+
+ def test_min(self):
+ from numpy import array
+ a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
+ assert a.min() == -3.0
+ b = array([])
+ raises(ValueError, "b.min()")
+
+ def test_argmax(self):
+ from numpy import array
+ a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
+ assert a.argmax() == 2
+ b = array([])
+ raises(ValueError, "b.argmax()")
+
+ def test_argmin(self):
+ from numpy import array
+ a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
+ assert a.argmin() == 3
+ b = array([])
+ raises(ValueError, "b.argmin()")
+
+ def test_all(self):
+ from numpy import array
+ a = array(range(5))
+ assert a.all() == False
+ a[0] = 3.0
+ assert a.all() == True
+ b = array([])
+ assert b.all() == True
+
+ def test_any(self):
+ from numpy import array, zeros
+ a = array(range(5))
+ assert a.any() == True
+ b = zeros(5)
+ assert b.any() == False
+ c = array([])
+ assert c.any() == False
+
+ def test_dot(self):
+ from numpy import array
+ a = array(range(5))
+ assert a.dot(a) == 30.0
+
+ def test_dot_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a.dot(2.5)
+ for i in xrange(5):
+ assert b[i] == 2.5*a[i]
+
+
+class AppTestSupport(object):
+ def setup_class(cls):
+ import struct
+ cls.space = gettestobjspace(usemodules=('micronumpy',))
+ cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4))
+
+ def test_fromstring(self):
+ from numpy import fromstring
+ a = fromstring(self.data)
+ for i in range(4):
+ assert a[i] == i + 1
+ raises(ValueError, fromstring, "abc")
+
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
@@ -10,6 +10,40 @@
assert sign(-0.0) == 0.0
assert minimum(2.0, 3.0) == 2.0
+ def test_sequence(self):
+ from numpy import array, negative, minimum
+ a = array(range(3))
+ b = [2.0, 1.0, 0.0]
+ c = 1.0
+ b_neg = negative(b)
+ assert isinstance(b_neg, array)
+ for i in range(3):
+ assert b_neg[i] == -b[i]
+ min_a_b = minimum(a, b)
+ assert isinstance(min_a_b, array)
+ for i in range(3):
+ assert min_a_b[i] == min(a[i], b[i])
+ min_b_a = minimum(b, a)
+ assert isinstance(min_b_a, array)
+ for i in range(3):
+ assert min_b_a[i] == min(a[i], b[i])
+ min_a_c = minimum(a, c)
+ assert isinstance(min_a_c, array)
+ for i in range(3):
+ assert min_a_c[i] == min(a[i], c)
+ min_c_a = minimum(c, a)
+ assert isinstance(min_c_a, array)
+ for i in range(3):
+ assert min_c_a[i] == min(a[i], c)
+ min_b_c = minimum(b, c)
+ assert isinstance(min_b_c, array)
+ for i in range(3):
+ assert min_b_c[i] == min(b[i], c)
+ min_c_b = minimum(c, b)
+ assert isinstance(min_c_b, array)
+ for i in range(3):
+ assert min_c_b[i] == min(b[i], c)
+
def test_negative(self):
from numpy import array, negative
@@ -31,6 +65,33 @@
for i in range(3):
assert b[i] == abs(a[i])
+ def test_add(self):
+ from numpy import array, add
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = add(a, b)
+ for i in range(3):
+ assert c[i] == a[i] + b[i]
+
+ def test_divide(self):
+ from numpy import array, divide
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = divide(a, b)
+ for i in range(3):
+ assert c[i] == a[i] / b[i]
+
+ def test_fabs(self):
+ from numpy import array, fabs
+ from math import fabs as math_fabs
+
+ a = array([-5.0, -0.0, 1.0])
+ b = fabs(a)
+ for i in range(3):
+ assert b[i] == math_fabs(a[i])
+
def test_minimum(self):
from numpy import array, minimum
@@ -49,6 +110,15 @@
for i in range(3):
assert c[i] == max(a[i], b[i])
+ def test_multiply(self):
+ from numpy import array, multiply
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = multiply(a, b)
+ for i in range(3):
+ assert c[i] == a[i] * b[i]
+
def test_sign(self):
from numpy import array, sign
@@ -67,6 +137,15 @@
for i in range(4):
assert b[i] == reference[i]
+ def test_subtract(self):
+ from numpy import array, subtract
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = subtract(a, b)
+ for i in range(3):
+ assert c[i] == a[i] - b[i]
+
def test_floor(self):
from numpy import array, floor
@@ -99,3 +178,30 @@
except OverflowError:
res = float('inf')
assert b[i] == res
+
+ def test_sin(self):
+ import math
+ from numpy import array, sin
+
+ a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2])
+ b = sin(a)
+ for i in range(len(a)):
+ assert b[i] == math.sin(a[i])
+
+ def test_cos(self):
+ import math
+ from numpy import array, cos
+
+ a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2])
+ b = cos(a)
+ for i in range(len(a)):
+ assert b[i] == math.cos(a[i])
+
+ def test_tan(self):
+ import math
+ from numpy import array, tan
+
+ a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2])
+ b = tan(a)
+ for i in range(len(a)):
+ assert b[i] == math.tan(a[i])
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
@@ -1,20 +1,30 @@
from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.rpython.test.test_llinterp import interpret
from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature,
- FloatWrapper, Call1, Call2, SingleDimSlice, add, mul)
+ FloatWrapper, Call2, SingleDimSlice, add, mul, Call1)
from pypy.module.micronumpy.interp_ufuncs import negative
from pypy.module.micronumpy.compile import numpy_compile
+from pypy.rlib.objectmodel import specialize
+from pypy.rlib.nonconst import NonConstant
class FakeSpace(object):
- pass
+ w_ValueError = None
+
+ def issequence_w(self, w_obj):
+ return True
+
+ @specialize.argtype(1)
+ def wrap(self, w_obj):
+ return w_obj
+
+ def float_w(self, w_obj):
+ return float(w_obj)
class TestNumpyJIt(LLJitMixin):
def setup_class(cls):
cls.space = FakeSpace()
def test_add(self):
- space = self.space
-
def f(i):
ar = SingleDimArray(i)
v = Call2(add, ar, ar, Signature())
@@ -27,8 +37,6 @@
assert result == f(5)
def test_floatadd(self):
- space = self.space
-
def f(i):
ar = SingleDimArray(i)
v = Call2(add, ar, FloatWrapper(4.5), Signature())
@@ -40,11 +48,118 @@
"int_lt": 1, "guard_true": 1, "jump": 1})
assert result == f(5)
- def test_already_forecd(self):
+ def test_sum(self):
space = self.space
def f(i):
ar = SingleDimArray(i)
+ return ar.descr_add(space, ar).descr_sum(space)
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 2,
+ "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1})
+ assert result == f(5)
+
+ def test_prod(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ return ar.descr_add(space, ar).descr_prod(space)
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
+ "float_mul": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1})
+ assert result == f(5)
+
+ def test_max(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ j = 0
+ while j < i:
+ ar.get_concrete().storage[j] = float(j)
+ j += 1
+ return ar.descr_add(space, ar).descr_max(space)
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
+ "float_gt": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1,
+ "guard_false": 1, "jump": 1})
+ assert result == f(5)
+
+ def test_min(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ j = 0
+ while j < i:
+ ar.get_concrete().storage[j] = float(j)
+ j += 1
+ return ar.descr_add(space, ar).descr_min(space)
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
+ "float_lt": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 2,
+ "jump": 1})
+ assert result == f(5)
+
+ def test_argmin(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ j = 0
+ while j < i:
+ ar.get_concrete().storage[j] = float(j)
+ j += 1
+ return ar.descr_add(space, ar).descr_argmin(space)
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
+ "float_lt": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 2,
+ "jump": 1})
+ assert result == f(5)
+
+ def test_all(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ j = 0
+ while j < i:
+ ar.get_concrete().storage[j] = 1.0
+ j += 1
+ return ar.descr_add(space, ar).descr_all(space)
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
+ "int_add": 1, "float_ne": 1,
+ "int_lt": 1, "guard_true": 2, "jump": 1})
+ assert result == f(5)
+
+ def test_any(self):
+ space = self.space
+
+ def f(i):
+ ar = SingleDimArray(i)
+ return ar.descr_add(space, ar).descr_any(space)
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
+ "int_add": 1, "float_ne": 1, "guard_false": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1})
+ assert result == f(5)
+
+ def test_already_forecd(self):
+ def f(i):
+ ar = SingleDimArray(i)
v1 = Call2(add, ar, FloatWrapper(4.5), Signature())
v2 = Call2(mul, v1, FloatWrapper(4.5), Signature())
v1.force_if_needed()
@@ -95,8 +210,6 @@
self.check_loop_count(3)
def test_slice(self):
- space = self.space
-
def f(i):
step = 3
ar = SingleDimArray(step*i)
@@ -111,8 +224,6 @@
assert result == f(5)
def test_slice2(self):
- space = self.space
-
def f(i):
step1 = 2
step2 = 3
@@ -128,6 +239,28 @@
'int_lt': 1, 'guard_true': 1, 'jump': 1})
assert result == f(5)
+ def test_setslice(self):
+ space = self.space
+
+ def f(i):
+ step = NonConstant(3)
+ ar = SingleDimArray(step*i)
+ ar2 = SingleDimArray(i)
+ ar2.storage[1] = 5.5
+ if NonConstant(False):
+ arg = ar2
+ else:
+ arg = ar2.descr_add(space, ar2)
+ ar.setslice(space, 0, step*i, step, i, arg)
+ return ar.get_concrete().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({'getarrayitem_raw': 2,
+ 'float_add' : 1,
+ 'setarrayitem_raw': 1, 'int_add': 2,
+ 'int_lt': 1, 'guard_true': 1, 'jump': 1})
+ assert result == 11.0
+
class TestTranslation(object):
def test_compile(self):
x = numpy_compile('aa+f*f/a-', 10)
diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py
--- a/pypy/module/mmap/interp_mmap.py
+++ b/pypy/module/mmap/interp_mmap.py
@@ -1,21 +1,16 @@
-from pypy.rpython.tool import rffi_platform
-from pypy.rpython.lltypesystem import rffi, lltype
from pypy.interpreter.error import OperationError, wrap_oserror
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
from pypy.rlib import rmmap
from pypy.rlib.rmmap import RValueError, RTypeError, ROverflowError
-import sys
-import os
-import platform
-import stat
+
class W_MMap(Wrappable):
def __init__(self, space, mmap_obj):
self.space = space
self.mmap = mmap_obj
-
+
def close(self):
self.mmap.close()
diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -125,13 +125,13 @@
assert st.st_size == 14
assert st.st_nlink == 1
- #if sys.platform.startswith('linux2'):
+ #if sys.platform.startswith('linux'):
# # expects non-integer timestamps - it's unlikely that they are
# # all three integers
# assert ((st.st_atime, st.st_mtime, st.st_ctime) !=
# (st[7], st[8], st[9]))
# assert st.st_blksize * st.st_blocks >= st.st_size
- if sys.platform.startswith('linux2'):
+ if sys.platform.startswith('linux'):
assert hasattr(st, 'st_rdev')
def test_stat_float_times(self):
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -15,7 +15,6 @@
from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter.baseobjspace import ObjSpace, W_Root
from opcode import opmap
-from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.nonconst import NonConstant
from pypy.jit.metainterp.resoperation import rop
from pypy.module.pypyjit.interp_resop import debug_merge_point_from_boxes
@@ -45,9 +44,11 @@
ec.w_tracefunc is None)
def can_never_inline(next_instr, is_being_profiled, bytecode):
+ return False
+
+def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode):
return (bytecode.co_flags & CO_GENERATOR) != 0
-
def wrap_oplist(space, logops, operations):
list_w = []
for op in operations:
@@ -66,7 +67,7 @@
def on_compile(self, logger, looptoken, operations, type, next_instr,
is_being_profiled, ll_pycode):
from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
-
+
space = self.space
cache = space.fromcache(Cache)
if cache.in_recursion:
@@ -111,7 +112,9 @@
get_jitcell_at = get_jitcell_at,
set_jitcell_at = set_jitcell_at,
confirm_enter_jit = confirm_enter_jit,
- can_never_inline = can_never_inline)
+ can_never_inline = can_never_inline,
+ should_unroll_one_iteration =
+ should_unroll_one_iteration)
class __extend__(PyFrame):
@@ -170,7 +173,7 @@
# ____________________________________________________________
#
-# Public interface
+# Public interface
def set_param(space, __args__):
'''Configure the tunable JIT parameters.
@@ -212,7 +215,7 @@
class Cache(object):
in_recursion = False
-
+
def __init__(self, space):
self.w_compile_hook = space.w_None
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
@@ -1,9 +1,9 @@
from pypy.interpreter.typedef import TypeDef, interp_attrproperty
-from pypy.interpreter.baseobjspace import Wrappable, ObjSpace, W_Root
+from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.gateway import unwrap_spec, interp2app
from pypy.interpreter.pycode import PyCode
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype
from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
from pypy.rpython.lltypesystem.rclass import OBJECT
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
@@ -30,7 +30,6 @@
assert res == 8.0 * 300
loop, = log.loops_by_filename(self.filepath)
assert loop.match_by_id('fficall', """
- p16 = getfield_gc(ConstPtr(ptr15), descr=<.* .*Function.inst_name .*>)
guard_not_invalidated(descr=...)
i17 = force_token()
setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py
--- a/pypy/module/pypyjit/test_pypy_c/test_array.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_array.py
@@ -19,7 +19,7 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i7 = int_lt(i5, i6)
- guard_true(i7, descr=<Guard3>)
+ guard_true(i7, descr=...)
i9 = int_add(i5, 1)
--TICK--
jump(p0, p1, p2, p3, p4, i9, i6, descr=<Loop0>)
@@ -39,11 +39,12 @@
assert log.result == 19507200
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
+ guard_not_invalidated(descr=...)
i13 = int_lt(i7, i9)
- guard_true(i13, descr=<Guard3>)
+ guard_true(i13, descr=...)
i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>)
i16 = int_add_ovf(i8, i15)
- guard_no_overflow(descr=<Guard4>)
+ guard_no_overflow(descr=...)
i18 = int_add(i7, 1)
--TICK--
jump(p0, p1, p2, p3, p4, p5, i18, i16, p8, i9, i10, descr=<Loop0>)
@@ -68,16 +69,17 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i13 = int_lt(i8, 307200)
- guard_true(i13, descr=<Guard3>)
+ guard_true(i13, descr=...)
+ guard_not_invalidated(descr=...)
# the bound check guard on img has been killed (thanks to the asserts)
i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>)
i15 = int_add_ovf(i9, i14)
- guard_no_overflow(descr=<Guard4>)
+ guard_no_overflow(descr=...)
i17 = int_sub(i8, 640)
# the bound check guard on intimg has been killed (thanks to the asserts)
i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>)
i19 = int_add_ovf(i18, i15)
- guard_no_overflow(descr=<Guard5>)
+ guard_no_overflow(descr=...)
# on 64bit, there is a guard checking that i19 actually fits into 32bit
...
setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>)
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
@@ -80,19 +80,19 @@
#
assert entry_bridge.match_by_id('call', """
p29 = getfield_gc(ConstPtr(ptr28), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value .*>)
- guard_nonnull_class(p29, ConstClass(Function), descr=<Guard18>)
+ guard_nonnull_class(p29, ConstClass(Function), descr=...)
p33 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_code .*>)
- guard_value(p33, ConstPtr(ptr34), descr=<Guard19>)
+ guard_value(p33, ConstPtr(ptr34), descr=...)
p35 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_w_func_globals .*>)
p36 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_closure .*>)
p38 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
p39 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
i40 = force_token()
p41 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
- guard_isnull(p41, descr=<Guard20>)
+ guard_isnull(p41, descr=...)
i42 = getfield_gc(p38, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
i43 = int_is_zero(i42)
- guard_true(i43, descr=<Guard21>)
+ guard_true(i43, descr=...)
i50 = force_token()
""")
#
@@ -101,16 +101,16 @@
loop, = log.loops_by_id('call')
assert loop.match("""
i12 = int_lt(i5, i6)
- guard_true(i12, descr=<Guard3>)
+ guard_true(i12, descr=...)
i13 = force_token()
i15 = int_add(i5, 1)
i16 = int_add_ovf(i15, i7)
- guard_no_overflow(descr=<Guard4>)
+ guard_no_overflow(descr=...)
i18 = force_token()
i20 = int_add_ovf(i16, 1)
- guard_no_overflow(descr=<Guard5>)
+ guard_no_overflow(descr=...)
i21 = int_add_ovf(i20, i7)
- guard_no_overflow(descr=<Guard6>)
+ guard_no_overflow(descr=...)
--TICK--
jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=<Loop0>)
""")
@@ -146,14 +146,14 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i15 = int_lt(i6, i9)
- guard_true(i15, descr=<Guard3>)
- guard_not_invalidated(descr=<Guard4>)
+ guard_true(i15, descr=...)
+ guard_not_invalidated(descr=...)
i16 = force_token()
i17 = int_add_ovf(i10, i6)
- guard_no_overflow(descr=<Guard5>)
+ guard_no_overflow(descr=...)
i18 = force_token()
i19 = int_add_ovf(i10, i17)
- guard_no_overflow(descr=<Guard6>)
+ guard_no_overflow(descr=...)
--TICK--
jump(p0, p1, p2, p3, p4, p5, i19, p7, i17, i9, i10, p11, p12, p13, descr=<Loop0>)
""")
@@ -180,11 +180,11 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i14 = int_lt(i6, i9)
- guard_true(i14, descr=<Guard3>)
- guard_not_invalidated(descr=<Guard4>)
+ guard_true(i14, descr=...)
+ guard_not_invalidated(descr=...)
i15 = force_token()
i17 = int_add_ovf(i8, 1)
- guard_no_overflow(descr=<Guard5>)
+ guard_no_overflow(descr=...)
i18 = force_token()
--TICK--
jump(p0, p1, p2, p3, p4, i8, p7, i17, p8, i9, p10, p11, p12, descr=<Loop0>)
@@ -282,32 +282,30 @@
loop0, = log.loops_by_id('g1')
assert loop0.match_by_id('g1', """
i20 = force_token()
- setfield_gc(p4, i19, descr=<.*W_AbstractSeqIterObject.inst_index .*>)
i22 = int_add_ovf(i8, 3)
- guard_no_overflow(descr=<Guard.*>)
+ guard_no_overflow(descr=...)
""")
assert loop0.match_by_id('h1', """
i20 = force_token()
i22 = int_add_ovf(i8, 2)
- guard_no_overflow(descr=<Guard.*>)
+ guard_no_overflow(descr=...)
""")
assert loop0.match_by_id('g2', """
i27 = force_token()
i29 = int_add_ovf(i26, 3)
- guard_no_overflow(descr=<Guard.*>)
+ guard_no_overflow(descr=...)
""")
#
loop1, = log.loops_by_id('g3')
assert loop1.match_by_id('g3', """
i21 = force_token()
- setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>)
i23 = int_add_ovf(i9, 3)
- guard_no_overflow(descr=<Guard.*>)
+ guard_no_overflow(descr=...)
""")
assert loop1.match_by_id('h2', """
i25 = force_token()
i27 = int_add_ovf(i23, 2)
- guard_no_overflow(descr=<Guard.*>)
+ guard_no_overflow(descr=...)
""")
def test_stararg(self):
@@ -353,7 +351,7 @@
i13 = getfield_gc(p8, descr=<SignedFieldDescr list.length .*>)
i15 = int_add(i13, 1)
call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=<VoidCallDescr>)
- guard_no_exception(descr=<Guard4>)
+ guard_no_exception(descr=...)
p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
p19 = new_with_vtable(ConstClass(W_IntObject))
setfield_gc(p19, i12, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
@@ -405,9 +403,9 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i10 = int_lt(i5, i6)
- guard_true(i10, descr=<Guard3>)
+ guard_true(i10, descr=...)
+ guard_not_invalidated(descr=...)
i120 = int_add(i5, 1)
- guard_not_invalidated(descr=<Guard4>)
--TICK--
jump(..., descr=<Loop0>)
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -23,3 +23,29 @@
ops = loop.ops_by_id('look')
assert log.opnames(ops) == ['setfield_gc',
'guard_not_invalidated']
+
+ def test_identitydict(self):
+ def fn(n):
+ class X(object):
+ pass
+ x = X()
+ d = {}
+ d[x] = 1
+ res = 0
+ for i in range(300):
+ value = d[x] # ID: getitem
+ res += value
+ return res
+ #
+ log = self.run(fn, [1000])
+ assert log.result == 300
+ loop, = log.loops_by_filename(self.filepath)
+ # check that the call to ll_dict_lookup is not a call_may_force
+ assert loop.match_by_id("getitem", """
+ i25 = call(ConstClass(_ll_1_gc_identityhash__objectPtr), p6, descr=...)
+ ...
+ i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...)
+ ...
+ p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...)
+ ...
+ """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py
--- a/pypy/module/pypyjit/test_pypy_c/test_exception.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py
@@ -36,11 +36,11 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i5 = int_is_true(i3)
- guard_true(i5, descr=<Guard3>)
- guard_not_invalidated(descr=<Guard4>)
+ guard_true(i5, descr=...)
+ guard_not_invalidated(descr=...)
--EXC-TICK--
i12 = int_sub_ovf(i3, 1)
- guard_no_overflow(descr=<Guard6>)
+ guard_no_overflow(descr=...)
--TICK--
jump(..., descr=<Loop0>)
""")
@@ -84,8 +84,8 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i7 = int_lt(i4, i5)
- guard_true(i7, descr=<Guard3>)
- guard_not_invalidated(descr=<Guard4>)
+ guard_true(i7, descr=...)
+ guard_not_invalidated(descr=...)
--EXC-TICK--
i14 = int_add(i4, 1)
--TICK--
diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py
@@ -0,0 +1,25 @@
+from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+
+
+class TestGenerators(BaseTestPyPyC):
+ def test_simple_generator(self):
+ def main(n):
+ def f():
+ for i in range(10000):
+ yield i
+
+ def g():
+ for i in f(): # ID: generator
+ pass
+
+ g()
+
+ log = self.run(main, [500])
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match_by_id("generator", """
+ i16 = force_token()
+ p45 = new_with_vtable(ConstClass(W_IntObject))
+ setfield_gc(p45, i29, descr=<SignedFieldDescr .*>)
+ setarrayitem_gc(p8, 0, p45, descr=<GcPtrArrayDescr>)
+ jump(..., descr=...)
+ """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py
@@ -0,0 +1,30 @@
+from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+
+
+class TestGlobals(BaseTestPyPyC):
+ def test_load_builtin(self):
+ def main(n):
+ import pypyjit
+
+ i = 0
+ while i < n:
+ l = len # ID: loadglobal
+ i += pypyjit.residual_call(l, "a")
+ return i
+ #
+ log = self.run(main, [500])
+ assert log.result == 500
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match_by_id("loadglobal", """
+ p10 = getfield_gc(p0, descr=<GcPtrFieldDescr .*Frame.inst_w_globals .*>)
+ guard_value(p10, ConstPtr(ptr11), descr=...)
+ p12 = getfield_gc(p10, descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+ guard_value(p12, ConstPtr(ptr13), descr=...)
+ p15 = getfield_gc(ConstPtr(ptr14), descr=<GcPtrFieldDescr .*ModuleCell.inst_w_value .*>)
+ guard_isnull(p15, descr=...)
+ guard_not_invalidated(descr=...)
+ p19 = getfield_gc(ConstPtr(p17), descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+ guard_value(p19, ConstPtr(ptr20), descr=...)
+ p22 = getfield_gc(ConstPtr(ptr21), descr=<GcPtrFieldDescr .*ModuleCell.inst_w_value .*>)
+ guard_nonnull(p22, descr=...)
+ """)
\ No newline at end of file
diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py
--- a/pypy/module/pypyjit/test_pypy_c/test_import.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_import.py
@@ -15,13 +15,13 @@
assert log.result == 500
loop, = log.loops_by_id('import')
assert loop.match_by_id('import', """
+ guard_not_invalidated(descr=...)
p11 = getfield_gc(ConstPtr(ptr10), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>)
- guard_value(p11, ConstPtr(ptr12), descr=<Guard4>)
- guard_not_invalidated(descr=<Guard5>)
+ guard_value(p11, ConstPtr(ptr12), descr=...)
p14 = getfield_gc(ConstPtr(ptr13), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>)
p16 = getfield_gc(ConstPtr(ptr15), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>)
- guard_value(p14, ConstPtr(ptr17), descr=<Guard6>)
- guard_isnull(p16, descr=<Guard7>)
+ guard_value(p14, ConstPtr(ptr17), descr=...)
+ guard_isnull(p16, descr=...)
""")
def test_import_fast_path(self, tmpdir):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -22,10 +22,10 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i7 = int_lt(i5, i6)
- guard_true(i7, descr=<Guard3>)
- guard_not_invalidated(descr=<Guard4>)
+ guard_true(i7, descr=...)
+ guard_not_invalidated(descr=...)
i9 = int_add_ovf(i5, 2)
- guard_no_overflow(descr=<Guard5>)
+ guard_no_overflow(descr=...)
--TICK--
jump(p0, p1, p2, p3, p4, i9, i6, descr=<Loop0>)
""")
@@ -47,10 +47,10 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i9 = int_lt(i5, i6)
- guard_true(i9, descr=<Guard3>)
- guard_not_invalidated(descr=<Guard4>)
+ guard_true(i9, descr=...)
+ guard_not_invalidated(descr=...)
i10 = int_add_ovf(i5, i7)
- guard_no_overflow(descr=<Guard5>)
+ guard_no_overflow(descr=...)
--TICK--
jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=<Loop0>)
""")
@@ -115,7 +115,7 @@
# ----------------------
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i9 = int_lt(i7, i8)
+ i9 = int_lt(i8, i7)
guard_true(i9, descr=.*)
guard_not_invalidated(descr=.*)
i11 = int_add(i8, 1)
@@ -124,7 +124,7 @@
p20 = new_with_vtable(ConstClass(W_IntObject))
More information about the pypy-commit
mailing list