[pypy-commit] pypy arm-backend-2: merge up to a98d7b4c1f16
bivab
noreply at buildbot.pypy.org
Fri Jul 1 16:16:02 CEST 2011
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r45231:4a6d9d2ae42a
Date: 2011-07-01 15:45 +0200
http://bitbucket.org/pypy/pypy/changeset/4a6d9d2ae42a/
Log: merge up to a98d7b4c1f16
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -25,6 +25,8 @@
^pypy/translator/c/src/libffi_msvc/.+\.dll$
^pypy/translator/c/src/libffi_msvc/.+\.lib$
^pypy/translator/c/src/libffi_msvc/.+\.exp$
+^pypy/translator/c/src/cjkcodecs/.+\.o$
+^pypy/translator/c/src/cjkcodecs/.+\.obj$
^pypy/translator/jvm/\.project$
^pypy/translator/jvm/\.classpath$
^pypy/translator/jvm/eclipse-bin$
diff --git a/README b/README
--- a/README
+++ b/README
@@ -15,10 +15,10 @@
The getting-started document will help guide you:
- http://codespeak.net/pypy/dist/pypy/doc/getting-started.html
+ http://doc.pypy.org/en/latest/getting-started.html
It will also point you to the rest of the documentation which is generated
from files in the pypy/doc directory within the source repositories. Enjoy
and send us feedback!
- the pypy-dev team <pypy-dev at codespeak.net>
+ the pypy-dev team <pypy-dev at python.org>
diff --git a/lib-python/TODO b/lib-python/TODO
deleted file mode 100644
--- a/lib-python/TODO
+++ /dev/null
@@ -1,100 +0,0 @@
-TODO list for 2.7.0
-===================
-
-You can find the results of the most recent buildbot run at:
-http://buildbot.pypy.org/
-
-
-Probably easy tasks
--------------------
-
-- (unicode|bytearray).(index|find) should accept None as indices (see
- test_unicode.py)
-
-- missing posix.confstr and posix.confstr_names
-
-- remove code duplication: bit_length() and _count_bits() in rlib/rbigint.py,
- objspace/std/longobject.py and objspace/std/longtype.py.
-
-- missing module pyexpat.errors
-
-- support for PYTHONIOENCODING, this needs a way to update file.encoding
-
-- implement format__Complex_ANY() in pypy/objspace/std/complexobject.py
-
-- Code like this does not work, for two reasons::
-
- \
- from __future__ import (with_statement,
- unicode_literals)
- assert type("") is unicode
-
-- Code like::
-
- assert(x is not None, "error message")
-
- should emit a SyntaxWarning when compiled (the tuple is always true)
-
-
-Medium tasks
-------------
-
-- socket module has a couple of changes (including AF_TIPC packet range)
-
-Longer tasks
-------------
-
-- Fix usage of __cmp__ in subclasses::
-
- class badint(int):
- def __cmp__(self, other):
- raise RuntimeError
- raises(RuntimeError, cmp, 0, badint(1))
-
-- Fix comparison of objects layout: if two classes have the same __slots__, it
- should be possible to change the instances __class__::
-
- class A(object): __slots__ = ('a', 'b')
- class B(object): __slots__ = ('b', 'a')
- a = A()
- a.__class__ = B
-
-- Show a ResourceWarning when a file/socket is not explicitely closed, like
- CPython did for 3.2: http://svn.python.org/view?view=rev&revision=85920
- in PyPy this should be enabled by default
-
-Won't do for this release
--------------------------
-
-Note: when you give up with a missing feature, please mention it here, as well
-as the various skips added to the test suite.
-
-- py3k warnings
-
- * the -3 flag is accepted on the command line, but displays a warning (see
- `translator/goal/app_main.py`)
-
-- CJK codecs.
-
- * In `./conftest.py`, skipped all `test_codecencodings_*.py` and
- `test_codecmaps_*.py`.
-
- * In test_codecs, commented out various items in `all_unicode_encodings`.
-
-- Error messages about ill-formed calls (like "argument after ** must be a
- mapping") don't always show the function name. That's hard to fix for
- the case of errors raised when the Argument object is created (as opposed
- to when parsing for a given target function, which occurs later).
-
- * Some "..." were added to doctests in test_extcall.py
-
-- CPython's builtin methods are both functions and unbound methods (for
- example, `str.upper is dict(str.__dict__)['upper']`). This is not the case
- in pypy, and assertions like `object.__str__ is object.__str__` are False
- with pypy. Use the `==` operator instead.
-
- * pprint.py, _threading_local.py
-
-- When importing a nested module fails, the ImportError message mentions the
- name of the package up to the component that could not be imported (CPython
- prefers to display the names starting with the failing part).
diff --git a/lib-python/modified-2.7/distutils/sysconfig.py b/lib-python/modified-2.7/distutils/sysconfig.py
--- a/lib-python/modified-2.7/distutils/sysconfig.py
+++ b/lib-python/modified-2.7/distutils/sysconfig.py
@@ -20,8 +20,10 @@
if '__pypy__' in sys.builtin_module_names:
from distutils.sysconfig_pypy import *
from distutils.sysconfig_pypy import _config_vars # needed by setuptools
+ from distutils.sysconfig_pypy import _variable_rx # read_setup_file()
else:
from distutils.sysconfig_cpython import *
from distutils.sysconfig_cpython import _config_vars # needed by setuptools
+ from distutils.sysconfig_cpython import _variable_rx # read_setup_file()
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,3 +116,7 @@
if compiler.compiler_type == "unix":
compiler.compiler_so.extend(['-fPIC', '-Wimplicit'])
compiler.shared_lib_extension = get_config_var('SO')
+
+from sysconfig_cpython import (
+ parse_makefile, _variable_rx, expand_makefile_vars)
+
diff --git a/lib_pypy/_pypy_wait.py b/lib_pypy/_pypy_wait.py
--- a/lib_pypy/_pypy_wait.py
+++ b/lib_pypy/_pypy_wait.py
@@ -6,12 +6,12 @@
libc = CDLL(find_library("c"))
c_wait3 = libc.wait3
-
c_wait3.argtypes = [POINTER(c_int), c_int, POINTER(_struct_rusage)]
+c_wait3.restype = c_int
c_wait4 = libc.wait4
-
c_wait4.argtypes = [c_int, POINTER(c_int), c_int, POINTER(_struct_rusage)]
+c_wait4.restype = c_int
def create_struct_rusage(c_struct):
return struct_rusage((
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -127,8 +127,6 @@
SQLITE_FUNCTION = 31
# SQLite C API
-sqlite.sqlite3_bind_double.argtypes = [c_void_p, c_int, c_double]
-sqlite.sqlite3_bind_int64.argtypes = [c_void_p, c_int, c_int64]
sqlite.sqlite3_value_int.argtypes = [c_void_p]
sqlite.sqlite3_value_int.restype = c_int
@@ -151,7 +149,16 @@
sqlite.sqlite3_value_type.argtypes = [c_void_p]
sqlite.sqlite3_value_type.restype = c_int
+sqlite.sqlite3_bind_blob.argtypes = [c_void_p, c_int, c_void_p, c_int,c_void_p]
+sqlite.sqlite3_bind_blob.restype = c_int
+sqlite.sqlite3_bind_double.argtypes = [c_void_p, c_int, c_double]
+sqlite.sqlite3_bind_double.restype = c_int
sqlite.sqlite3_bind_int.argtypes = [c_void_p, c_int, c_int]
+sqlite.sqlite3_bind_int.restype = c_int
+sqlite.sqlite3_bind_int64.argtypes = [c_void_p, c_int, c_int64]
+sqlite.sqlite3_bind_int64.restype = c_int
+sqlite.sqlite3_bind_null.argtypes = [c_void_p, c_int]
+sqlite.sqlite3_bind_null.restype = c_int
sqlite.sqlite3_bind_parameter_count.argtypes = [c_void_p]
sqlite.sqlite3_bind_parameter_count.restype = c_int
sqlite.sqlite3_bind_parameter_index.argtypes = [c_void_p, c_char_p]
@@ -159,45 +166,69 @@
sqlite.sqlite3_bind_parameter_name.argtypes = [c_void_p, c_int]
sqlite.sqlite3_bind_parameter_name.restype = c_char_p
sqlite.sqlite3_bind_text.argtypes = [c_void_p, c_int, c_char_p, c_int,c_void_p]
-sqlite.sqlite3_bind_blob.argtypes = [c_void_p, c_int, c_void_p, c_int,c_void_p]
-sqlite.sqlite3_bind_blob.restype = c_int
+sqlite.sqlite3_bind_text.restype = c_int
+sqlite.sqlite3_busy_timeout.argtypes = [c_void_p, c_int]
+sqlite.sqlite3_busy_timeout.restype = c_int
sqlite.sqlite3_changes.argtypes = [c_void_p]
sqlite.sqlite3_changes.restype = c_int
sqlite.sqlite3_close.argtypes = [c_void_p]
sqlite.sqlite3_close.restype = c_int
+sqlite.sqlite3_column_blob.argtypes = [c_void_p, c_int]
sqlite.sqlite3_column_blob.restype = c_void_p
+sqlite.sqlite3_column_bytes.argtypes = [c_void_p, c_int]
sqlite.sqlite3_column_bytes.restype = c_int
+sqlite.sqlite3_column_count.argtypes = [c_void_p]
+sqlite.sqlite3_column_count.restype = c_int
+sqlite.sqlite3_column_decltype.argtypes = [c_void_p, c_int]
+sqlite.sqlite3_column_decltype.restype = c_char_p
+sqlite.sqlite3_column_double.argtypes = [c_void_p, c_int]
sqlite.sqlite3_column_double.restype = c_double
+sqlite.sqlite3_column_int64.argtypes = [c_void_p, c_int]
sqlite.sqlite3_column_int64.restype = c_int64
+sqlite.sqlite3_column_name.argtypes = [c_void_p, c_int]
sqlite.sqlite3_column_name.restype = c_char_p
+sqlite.sqlite3_column_text.argtypes = [c_void_p, c_int]
sqlite.sqlite3_column_text.restype = c_char_p
+sqlite.sqlite3_column_type.argtypes = [c_void_p, c_int]
+sqlite.sqlite3_column_type.restype = c_int
sqlite.sqlite3_complete.argtypes = [c_char_p]
sqlite.sqlite3_complete.restype = c_int
sqlite.sqlite3_errcode.restype = c_int
+sqlite.sqlite3_errmsg.argtypes = [c_void_p]
sqlite.sqlite3_errmsg.restype = c_char_p
+sqlite.sqlite3_finalize.argtypes = [c_void_p]
+sqlite.sqlite3_finalize.restype = c_int
sqlite.sqlite3_get_autocommit.argtypes = [c_void_p]
sqlite.sqlite3_get_autocommit.restype = c_int
+sqlite.sqlite3_last_insert_rowid.argtypes = [c_void_p]
+sqlite.sqlite3_last_insert_rowid.restype = c_int64
sqlite.sqlite3_libversion.argtypes = []
sqlite.sqlite3_libversion.restype = c_char_p
sqlite.sqlite3_open.argtypes = [c_char_p, c_void_p]
sqlite.sqlite3_open.restype = c_int
+sqlite.sqlite3_prepare.argtypes = [c_void_p, c_char_p, c_int, c_void_p, POINTER(c_char_p)]
+sqlite.sqlite3_prepare.restype = c_int
sqlite.sqlite3_prepare_v2.argtypes = [c_void_p, c_char_p, c_int, c_void_p, POINTER(c_char_p)]
sqlite.sqlite3_prepare_v2.restype = c_int
-sqlite.sqlite3_column_decltype.argtypes = [c_void_p, c_int]
-sqlite.sqlite3_column_decltype.restype = c_char_p
sqlite.sqlite3_step.argtypes = [c_void_p]
sqlite.sqlite3_step.restype = c_int
sqlite.sqlite3_reset.argtypes = [c_void_p]
sqlite.sqlite3_reset.restype = c_int
-sqlite.sqlite3_column_count.argtypes = [c_void_p]
-sqlite.sqlite3_column_count.restype = c_int
+sqlite.sqlite3_total_changes.argtypes = [c_void_p]
+sqlite.sqlite3_total_changes.restype = c_int
sqlite.sqlite3_result_blob.argtypes = [c_void_p, c_char_p, c_int, c_void_p]
+sqlite.sqlite3_result_blob.restype = None
sqlite.sqlite3_result_int64.argtypes = [c_void_p, c_int64]
+sqlite.sqlite3_result_int64.restype = None
sqlite.sqlite3_result_null.argtypes = [c_void_p]
+sqlite.sqlite3_result_null.restype = None
sqlite.sqlite3_result_double.argtypes = [c_void_p, c_double]
+sqlite.sqlite3_result_double.restype = None
sqlite.sqlite3_result_error.argtypes = [c_void_p, c_char_p, c_int]
+sqlite.sqlite3_result_error.restype = None
sqlite.sqlite3_result_text.argtypes = [c_void_p, c_char_p, c_int, c_void_p]
+sqlite.sqlite3_result_text.restype = None
##########################################
# END Wrapped SQLite C API and constants
diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py
--- a/lib_pypy/stackless.py
+++ b/lib_pypy/stackless.py
@@ -200,14 +200,15 @@
# I can't think of a better solution without a real transform.
def rewrite_stackless_primitive(coro_state, alive, tempval):
- flags, state, thunk, parent = coro_state
- for i, frame in enumerate(state):
+ flags, frame, thunk, parent = coro_state
+ while frame is not None:
retval_expr = _stackless_primitive_registry.get(frame.f_code)
if retval_expr:
# this tasklet needs to stop pickling here and return its value.
tempval = eval(retval_expr, globals(), frame.f_locals)
- state = state[:i]
- coro_state = flags, state, thunk, parent
+ coro_state = flags, frame, thunk, parent
+ break
+ frame = frame.f_back
return coro_state, alive, tempval
#
@@ -492,23 +493,22 @@
assert two == ()
# we want to get rid of the parent thing.
# for now, we just drop it
- a, b, c, d = coro_state
-
+ a, frame, c, d = coro_state
+
# Removing all frames related to stackless.py.
# They point to stuff we don't want to be pickled.
- frame_list = list(b)
- new_frame_list = []
- for frame in frame_list:
+
+ pickleframe = frame
+ while frame is not None:
if frame.f_code == schedule.func_code:
# Removing everything including and after the
# call to stackless.schedule()
+ pickleframe = frame.f_back
break
- new_frame_list.append(frame)
- b = tuple(new_frame_list)
-
+ frame = frame.f_back
if d:
assert isinstance(d, coroutine)
- coro_state = a, b, c, None
+ coro_state = a, pickleframe, c, None
coro_state, alive, tempval = rewrite_stackless_primitive(coro_state, self.alive, self.tempval)
inst_dict = self.__dict__.copy()
inst_dict.pop('tempval', None)
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -228,7 +228,7 @@
# graph -- it's already low-level operations!
for a, s_newarg in zip(graph.getargs(), cells):
s_oldarg = self.binding(a)
- assert s_oldarg.contains(s_newarg)
+ assert annmodel.unionof(s_oldarg, s_newarg) == s_oldarg
else:
assert not self.frozen
for a in cells:
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -565,7 +565,7 @@
if self.is_exception_class():
if self.pyobj.__module__ == 'exceptions':
return True
- if self.pyobj is py.code._AssertionError:
+ if issubclass(self.pyobj, AssertionError):
return True
return False
diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -32,13 +32,15 @@
import pypy
from pypy.tool import descriptor
from pypy.tool.pairtype import pair, extendabletype
-from pypy.tool.tls import tlsobject
from pypy.rlib.rarithmetic import r_uint, r_ulonglong, base_int
from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat
import inspect, weakref
DEBUG = False # set to False to disable recording of debugging information
-TLS = tlsobject()
+
+class State(object):
+ pass
+TLS = State()
class SomeObject(object):
"""The set of all objects. Each instance stands
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -33,7 +33,7 @@
"struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO",
"thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
"_bisect", "binascii", "_multiprocessing", '_warnings',
- "_collections", "_multibytecodec"]
+ "_collections", "_multibytecodec", "micronumpy"]
))
translation_modules = default_modules.copy()
@@ -242,6 +242,10 @@
"(the empty string and potentially single-char strings)",
default=False),
+ BoolOption("withsmalltuple",
+ "use small tuples",
+ default=False),
+
BoolOption("withrope", "use ropes as the string implementation",
default=False,
requires=[("objspace.std.withstrslice", False),
@@ -269,7 +273,7 @@
"make instances really small but slow without the JIT",
default=False,
requires=[("objspace.std.getattributeshortcut", True),
- ("objspace.std.withtypeversion", True),
+ ("objspace.std.withmethodcache", True),
]),
BoolOption("withrangelist",
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -221,17 +221,17 @@
StrOption("profile_based_inline",
"Use call count profiling to drive inlining"
", specify arguments",
- default=None, cmdline="--prof-based-inline"),
+ default=None), # cmdline="--prof-based-inline" fix me
FloatOption("profile_based_inline_threshold",
"Threshold when to inline functions "
"for profile based inlining",
default=DEFL_PROF_BASED_INLINE_THRESHOLD,
- cmdline="--prof-based-inline-threshold"),
+ ), # cmdline="--prof-based-inline-threshold" fix me
StrOption("profile_based_inline_heuristic",
"Dotted name of an heuristic function "
"for profile based inlining",
default="pypy.translator.backendopt.inline.inlining_heuristic",
- cmdline="--prof-based-inline-heuristic"),
+ ), # cmdline="--prof-based-inline-heuristic" fix me
# control clever malloc removal
BoolOption("clever_malloc_removal",
"Drives inlining to remove mallocs in a clever way",
diff --git a/pypy/conftest.py b/pypy/conftest.py
--- a/pypy/conftest.py
+++ b/pypy/conftest.py
@@ -46,6 +46,10 @@
group.addoption('-P', '--platform', action="callback", type="string",
default="host", callback=_set_platform,
help="set up tests to use specified platform as compile/run target")
+ group = parser.getgroup("JIT options")
+ group.addoption('--viewloops', action="store_true",
+ default=False, dest="viewloops",
+ help="show only the compiled loops")
def pytest_sessionstart():
# have python subprocesses avoid startup customizations by default
diff --git a/pypy/doc/config/objspace.std.withsmalltuple.txt b/pypy/doc/config/objspace.std.withsmalltuple.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.std.withsmalltuple.txt
@@ -0,0 +1,1 @@
+Use small tuple objects for sizes from 1 to 3
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
@@ -136,6 +136,11 @@
next access. Any code that uses weak proxies must carefully catch such
``ReferenceError`` at any place that uses them.
+As a side effect, the ``finally`` clause inside a generator will be executed
+only when the generator object is garbage collected (see `issue 736`__).
+
+.. __: http://bugs.pypy.org/issue736
+
There are a few extra implications for the difference in the GC. Most
notably, if an object has a ``__del__``, the ``__del__`` is never called more
than once in PyPy; but CPython will call the same ``__del__`` several times
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/project-ideas.rst
@@ -0,0 +1,49 @@
+
+Potential project list
+======================
+
+This is a list of projects that are interesting for potential contributors
+who are seriously interested in the PyPy project. They mostly share common
+patterns - they're mid-to-large in size, they're usually well defined as
+a standalone projects and they're not being actively worked on. For small
+projects that you might want to work on, it's much better to either look
+at the `issue tracker`_, pop up on #pypy on irc.freenode.net or write to the
+`mailing list`_. This is simply for the reason that small possible projects
+tend to change very rapidly.
+
+Numpy improvements
+------------------
+
+This is more of a project-container than a single project. Possible ideas:
+
+* experiment with auto-vectorization using SSE or implement vectorization
+ without automatically detecting it for array operations.
+
+* improve numpy, for example implement memory views.
+
+* interface with fortran/C libraries.
+
+Potential mentors: fijal
+
+JIT tooling
+-----------
+
+xxx
+
+Work on some of other languages
+-------------------------------
+
+xxx
+
+Various GCs
+-----------
+
+xxx
+
+Remove the GIL
+--------------
+
+xxx
+
+.. _`issue tracker`: ...
+.. _`mailing list`: ...
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
@@ -31,11 +31,12 @@
future_lineno = 0
future_column = 0
have_docstring = False
+ body = None
if isinstance(tree, ast.Module):
body = tree.body
elif isinstance(tree, ast.Interactive):
body = tree.body
- else:
+ if body is None:
return 0, 0
for stmt in body:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -82,7 +82,7 @@
raise
def getaddrstring(self, space):
- # XXX slowish
+ # slowish
w_id = space.id(self)
w_4 = space.wrap(4)
w_0x0F = space.wrap(0x0F)
@@ -616,7 +616,6 @@
def createcompiler(self):
"Factory function creating a compiler object."
- # XXX simple selection logic for now
try:
return self.default_compiler
except AttributeError:
@@ -821,11 +820,11 @@
def call_obj_args(self, w_callable, w_obj, args):
if not self.config.objspace.disable_call_speedhacks:
- # XXX start of hack for performance
+ # start of hack for performance
from pypy.interpreter.function import Function
if isinstance(w_callable, Function):
return w_callable.call_obj_args(w_obj, args)
- # XXX end of hack for performance
+ # end of hack for performance
return self.call_args(w_callable, args.prepend(w_obj))
def call(self, w_callable, w_args, w_kwds=None):
@@ -835,7 +834,7 @@
def call_function(self, w_func, *args_w):
nargs = len(args_w) # used for pruning funccall versions
if not self.config.objspace.disable_call_speedhacks and nargs < 5:
- # XXX start of hack for performance
+ # start of hack for performance
from pypy.interpreter.function import Function, Method
if isinstance(w_func, Method):
w_inst = w_func.w_instance
@@ -850,7 +849,7 @@
if isinstance(w_func, Function):
return w_func.funccall(*args_w)
- # XXX end of hack for performance
+ # end of hack for performance
args = Arguments(self, list(args_w))
return self.call_args(w_func, args)
@@ -864,7 +863,7 @@
return self.call_args_and_c_profile(frame, w_func, args)
if not self.config.objspace.disable_call_speedhacks:
- # XXX start of hack for performance
+ # start of hack for performance
if isinstance(w_func, Method):
w_inst = w_func.w_instance
if w_inst is not None:
@@ -879,7 +878,7 @@
if isinstance(w_func, Function):
return w_func.funccall_valuestack(nargs, frame)
- # XXX end of hack for performance
+ # end of hack for performance
args = frame.make_arguments(nargs)
return self.call_args(w_func, args)
@@ -1338,7 +1337,7 @@
source = source.lstrip()
assert source.startswith('('), "incorrect header in:\n%s" % (source,)
source = py.code.Source("def anonymous%s\n" % source)
- w_glob = space.newdict()
+ w_glob = space.newdict(module=True)
space.exec_(str(source), w_glob, w_glob)
return space.getitem(w_glob, space.wrap('anonymous'))
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -11,14 +11,14 @@
"""Interpreter-level exception that signals an exception that should be
sent to the application level.
- OperationError instances have three public attributes (and no .args),
- w_type, w_value and application_traceback, which contain the wrapped
+ OperationError instances have three attributes (and no .args),
+ w_type, _w_value and _application_traceback, which contain the wrapped
type and value describing the exception, and a chained list of
PyTraceback objects making the application-level traceback.
"""
_w_value = None
- application_traceback = None
+ _application_traceback = None
def __init__(self, w_type, w_value, tb=None):
if not we_are_translated() and w_type is None:
@@ -26,7 +26,7 @@
raise FlowingError(w_value)
self.setup(w_type)
self._w_value = w_value
- self.application_traceback = tb
+ self._application_traceback = tb
def setup(self, w_type):
self.w_type = w_type
@@ -37,7 +37,7 @@
# for sys.exc_clear()
self.w_type = space.w_None
self._w_value = space.w_None
- self.application_traceback = None
+ self._application_traceback = None
if not we_are_translated():
del self.debug_excs[:]
@@ -103,7 +103,7 @@
def print_app_tb_only(self, file):
"NOT_RPYTHON"
- tb = self.application_traceback
+ tb = self._application_traceback
if tb:
import linecache
print >> file, "Traceback (application-level):"
@@ -251,6 +251,30 @@
def _compute_value(self):
raise NotImplementedError
+ def get_traceback(self):
+ """Calling this marks the PyTraceback as escaped, i.e. it becomes
+ accessible and inspectable by app-level Python code. For the JIT.
+ Note that this has no effect if there are already several traceback
+ frames recorded, because in this case they are already marked as
+ escaping by executioncontext.leave() being called with
+ got_exception=True.
+ """
+ from pypy.interpreter.pytraceback import PyTraceback
+ tb = self._application_traceback
+ if tb is not None and isinstance(tb, PyTraceback):
+ tb.frame.mark_as_escaped()
+ return tb
+
+ def set_traceback(self, traceback):
+ """Set the current traceback. It should either be a traceback
+ pointing to some already-escaped frame, or a traceback for the
+ current frame. To support the latter case we do not mark the
+ frame as escaped. The idea is that it will be marked as escaping
+ only if the exception really propagates out of this frame, by
+ executioncontext.leave() being called with got_exception=True.
+ """
+ self._application_traceback = traceback
+
# ____________________________________________________________
# optimization only: avoid the slowest operation -- the string
# formatting with '%' -- in the common case were we don't
diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py
--- a/pypy/interpreter/eval.py
+++ b/pypy/interpreter/eval.py
@@ -2,6 +2,7 @@
This module defines the abstract base classes that support execution:
Code and Frame.
"""
+from pypy.rlib import jit
from pypy.interpreter.error import OperationError
from pypy.interpreter.baseobjspace import Wrappable
@@ -97,6 +98,7 @@
"Abstract. Get the expected number of locals."
raise TypeError, "abstract"
+ @jit.dont_look_inside
def fast2locals(self):
# Copy values from self.fastlocals_w to self.w_locals
if self.w_locals is None:
@@ -110,6 +112,7 @@
w_name = self.space.wrap(name)
self.space.setitem(self.w_locals, w_name, w_value)
+ @jit.dont_look_inside
def locals2fast(self):
# Copy values from self.w_locals to self.fastlocals_w
assert self.w_locals is not None
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -24,6 +24,8 @@
# XXX [fijal] but they're not. is_being_profiled is guarded a bit all
# over the place as well as w_tracefunc
+ _immutable_fields_ = ['profilefunc?', 'w_tracefunc?']
+
def __init__(self, space):
self.space = space
self.topframeref = jit.vref_None
@@ -56,13 +58,23 @@
frame.f_backref = self.topframeref
self.topframeref = jit.virtual_ref(frame)
- def leave(self, frame, w_exitvalue):
+ def leave(self, frame, w_exitvalue, got_exception):
try:
if self.profilefunc:
self._trace(frame, 'leaveframe', w_exitvalue)
finally:
+ frame_vref = self.topframeref
self.topframeref = frame.f_backref
- jit.virtual_ref_finish(frame)
+ if frame.escaped or got_exception:
+ # if this frame escaped to applevel, we must ensure that also
+ # f_back does
+ f_back = frame.f_backref()
+ if f_back:
+ f_back.mark_as_escaped()
+ # force the frame (from the JIT point of view), so that it can
+ # be accessed also later
+ frame_vref()
+ jit.virtual_ref_finish(frame_vref, frame)
if self.w_tracefunc is not None and not frame.hide():
self.space.frame_trace_action.fire()
@@ -100,18 +112,16 @@
# the following interface is for pickling and unpickling
def getstate(self, space):
- # XXX we could just save the top frame, which brings
- # the whole frame stack, but right now we get the whole stack
- items = [space.wrap(f) for f in self.getframestack()]
- return space.newtuple(items)
+ if self.topframe is None:
+ return space.w_None
+ return self.topframe
def setstate(self, space, w_state):
from pypy.interpreter.pyframe import PyFrame
- frames_w = space.unpackiterable(w_state)
- if len(frames_w) > 0:
- self.topframe = space.interp_w(PyFrame, frames_w[-1])
+ if space.is_w(w_state, space.w_None):
+ self.topframe = None
else:
- self.topframe = None
+ self.topframe = space.interp_w(PyFrame, w_state)
def getframestack(self):
lst = []
@@ -276,7 +286,7 @@
if operr is not None:
w_value = operr.get_w_value(space)
w_arg = space.newtuple([operr.w_type, w_value,
- space.wrap(operr.application_traceback)])
+ space.wrap(operr.get_traceback())])
frame.fast2locals()
self.is_tracing += 1
diff --git a/pypy/interpreter/main.py b/pypy/interpreter/main.py
--- a/pypy/interpreter/main.py
+++ b/pypy/interpreter/main.py
@@ -118,7 +118,7 @@
operationerr.normalize_exception(space)
w_type = operationerr.w_type
w_value = operationerr.get_w_value(space)
- w_traceback = space.wrap(operationerr.application_traceback)
+ w_traceback = space.wrap(operationerr.get_traceback())
# for debugging convenience we also insert the exception into
# the interpreter-level sys.last_xxx
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -127,6 +127,7 @@
if self.cells is not None:
self.cells[:ncellvars] = cellvars
+ @jit.dont_look_inside
def fast2locals(self):
super_fast2locals(self)
# cellvars are values exported to inner scopes
@@ -145,6 +146,7 @@
w_name = self.space.wrap(name)
self.space.setitem(self.w_locals, w_name, w_value)
+ @jit.dont_look_inside
def locals2fast(self):
super_locals2fast(self)
freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -101,9 +101,9 @@
"""
def __init__(self, space, override_version=None):
PyCodeCompiler.__init__(self, space)
- self.parser = pyparse.PythonParser(space)
+ self.future_flags = future.futureFlags_2_7
+ self.parser = pyparse.PythonParser(space, self.future_flags)
self.additional_rules = {}
- self.future_flags = future.futureFlags_2_7
self.compiler_flags = self.future_flags.allowed_flags
def compile_ast(self, node, filename, mode, flags):
@@ -140,9 +140,6 @@
def _compile_to_ast(self, source, info):
space = self.space
try:
- f_flags, future_info = future.get_futures(self.future_flags, source)
- info.last_future_import = future_info
- info.flags |= f_flags
parse_tree = self.parser.parse_source(source, info)
mod = astbuilder.ast_from_node(space, parse_tree, info)
except parseerror.IndentationError, e:
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -11,7 +11,7 @@
from pypy.rlib.jit import hint
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib.rarithmetic import intmask
-from pypy.rlib import jit, rstack
+from pypy.rlib import jit
from pypy.tool import stdlib_opcode
from pypy.tool.stdlib_opcode import host_bytecode_spec
@@ -49,6 +49,7 @@
instr_ub = 0
instr_prev_plus_one = 0
is_being_profiled = False
+ escaped = False # see mark_as_escaped()
def __init__(self, space, code, w_globals, closure):
self = hint(self, access_directly=True, fresh_virtualizable=True)
@@ -67,6 +68,15 @@
make_sure_not_resized(self.fastlocals_w)
self.f_lineno = code.co_firstlineno
+ def mark_as_escaped(self):
+ """
+ Must be called on frames that are exposed to applevel, e.g. by
+ sys._getframe(). This ensures that the virtualref holding the frame
+ is properly forced by ec.leave(), and thus the frame will be still
+ accessible even after the corresponding C stack died.
+ """
+ self.escaped = True
+
def append_block(self, block):
block.previous = self.lastblock
self.lastblock = block
@@ -138,6 +148,7 @@
not self.space.config.translating)
executioncontext = self.space.getexecutioncontext()
executioncontext.enter(self)
+ got_exception = True
w_exitvalue = self.space.w_None
try:
executioncontext.call_trace(self)
@@ -157,8 +168,6 @@
try:
w_exitvalue = self.dispatch(self.pycode, next_instr,
executioncontext)
- rstack.resume_point("execute_frame", self, executioncontext,
- returns=w_exitvalue)
except Exception:
executioncontext.return_trace(self, self.space.w_None)
raise
@@ -166,8 +175,9 @@
# clean up the exception, might be useful for not
# allocating exception objects in some cases
self.last_exception = None
+ got_exception = False
finally:
- executioncontext.leave(self, w_exitvalue)
+ executioncontext.leave(self, w_exitvalue, got_exception)
return w_exitvalue
execute_frame.insert_stack_check_here = True
@@ -314,7 +324,7 @@
w_tb = space.w_None
else:
w_exc_value = self.last_exception.get_w_value(space)
- w_tb = w(self.last_exception.application_traceback)
+ w_tb = w(self.last_exception.get_traceback())
tup_state = [
w(self.f_backref()),
@@ -415,6 +425,7 @@
"Get the fast locals as a list."
return self.fastlocals_w
+ @jit.dont_look_inside
def setfastscope(self, scope_w):
"""Initialize the fast locals from a list of values,
where the order is according to self.pycode.signature()."""
@@ -634,7 +645,7 @@
while f is not None and f.last_exception is None:
f = f.f_backref()
if f is not None:
- return space.wrap(f.last_exception.application_traceback)
+ return space.wrap(f.last_exception.get_traceback())
return space.w_None
def fget_f_restricted(self, space):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -11,7 +11,7 @@
from pypy.interpreter.pycode import PyCode
from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib import jit, rstackovf, rstack
+from pypy.rlib import jit, rstackovf
from pypy.rlib.rarithmetic import r_uint, intmask
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import check_nonneg
@@ -83,16 +83,12 @@
try:
while True:
next_instr = self.handle_bytecode(co_code, next_instr, ec)
- rstack.resume_point("dispatch", self, co_code, ec,
- returns=next_instr)
except ExitFrame:
return self.popvalue()
def handle_bytecode(self, co_code, next_instr, ec):
try:
next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
- rstack.resume_point("handle_bytecode", self, co_code, ec,
- returns=next_instr)
except OperationError, operr:
next_instr = self.handle_operation_error(ec, operr)
except Reraise:
@@ -248,9 +244,6 @@
# dispatch to the opcode method
meth = getattr(self, opdesc.methodname)
res = meth(oparg, next_instr)
- if opdesc.index == self.opcodedesc.CALL_FUNCTION.index:
- rstack.resume_point("dispatch_call", self, co_code,
- next_instr, ec)
# !! warning, for the annotator the next line is not
# comparing an int and None - you can't do that.
# Instead, it's constant-folded to either True or False
@@ -573,7 +566,7 @@
else:
msg = "raise: arg 3 must be a traceback or None"
tb = pytraceback.check_traceback(space, w_traceback, msg)
- operror.application_traceback = tb
+ operror.set_traceback(tb)
# special 3-arguments raise, no new traceback obj will be attached
raise RaiseWithExplicitTraceback(operror)
@@ -953,7 +946,7 @@
isinstance(unroller, SApplicationException))
if is_app_exc:
operr = unroller.operr
- w_traceback = self.space.wrap(operr.application_traceback)
+ w_traceback = self.space.wrap(operr.get_traceback())
w_suppress = self.call_contextmanager_exit_function(
w_exitfunc,
operr.w_type,
@@ -997,7 +990,6 @@
args)
else:
w_result = self.space.call_args(w_function, args)
- rstack.resume_point("call_function", self, returns=w_result)
self.pushvalue(w_result)
def CALL_FUNCTION(self, oparg, next_instr):
@@ -1008,8 +1000,6 @@
w_function = self.peekvalue(nargs)
try:
w_result = self.space.call_valuestack(w_function, nargs, self)
- rstack.resume_point("CALL_FUNCTION", self, nargs,
- returns=w_result)
finally:
self.dropvalues(nargs + 1)
self.pushvalue(w_result)
@@ -1099,6 +1089,7 @@
w_dict = self.space.newdict()
self.pushvalue(w_dict)
+ @jit.unroll_safe
def BUILD_SET(self, itemcount, next_instr):
w_set = self.space.call_function(self.space.w_set)
if itemcount:
diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py
--- a/pypy/interpreter/pyparser/pyparse.py
+++ b/pypy/interpreter/pyparser/pyparse.py
@@ -1,6 +1,6 @@
from pypy.interpreter import gateway
from pypy.interpreter.error import OperationError
-from pypy.interpreter.pyparser import parser, pytokenizer, pygram, error
+from pypy.interpreter.pyparser import future, parser, pytokenizer, pygram, error
from pypy.interpreter.astcompiler import consts
@@ -88,9 +88,11 @@
class PythonParser(parser.Parser):
- def __init__(self, space, grammar=pygram.python_grammar):
+ def __init__(self, space, future_flags=future.futureFlags_2_7,
+ grammar=pygram.python_grammar):
parser.Parser.__init__(self, grammar)
self.space = space
+ self.future_flags = future_flags
def parse_source(self, textsrc, compile_info):
"""Main entry point for parsing Python source.
@@ -133,6 +135,10 @@
raise error.SyntaxError(space.str_w(w_message))
raise
+ f_flags, future_info = future.get_futures(self.future_flags, textsrc)
+ compile_info.last_future_import = future_info
+ compile_info.flags |= f_flags
+
flags = compile_info.flags
if flags & consts.CO_FUTURE_PRINT_FUNCTION:
diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py
--- a/pypy/interpreter/pytraceback.py
+++ b/pypy/interpreter/pytraceback.py
@@ -51,9 +51,9 @@
def record_application_traceback(space, operror, frame, last_instruction):
if frame.pycode.hidden_applevel:
return
- tb = operror.application_traceback
+ tb = operror.get_traceback()
tb = PyTraceback(space, frame, last_instruction, tb)
- operror.application_traceback = tb
+ operror.set_traceback(tb)
def offset2lineno(c, stopat):
tab = c.co_lnotab
diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -714,6 +714,12 @@
class AppTestCompiler:
+ def test_bom_with_future(self):
+ s = '\xef\xbb\xbffrom __future__ import division\nx = 1/2'
+ ns = {}
+ exec s in ns
+ assert ns["x"] == .5
+
def test_values_of_different_types(self):
exec "a = 0; b = 0L; c = 0.0; d = 0j"
assert type(a) is int
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -98,6 +98,15 @@
return sys._getframe().f_back.f_code.co_name
f()
+ def test_f_back_virtualref(self):
+ import sys
+ def f():
+ return g()
+ def g():
+ return sys._getframe()
+ frame = f()
+ assert frame.f_back.f_code.co_name == 'f'
+
def test_f_exc_xxx(self):
import sys
@@ -122,6 +131,21 @@
except:
g(sys.exc_info())
+ def test_virtualref_through_traceback(self):
+ import sys
+ def g():
+ try:
+ raise ValueError
+ except:
+ _, _, tb = sys.exc_info()
+ return tb
+ def f():
+ return g()
+ #
+ tb = f()
+ assert tb.tb_frame.f_code.co_name == 'g'
+ assert tb.tb_frame.f_back.f_code.co_name == 'f'
+
def test_trace_basic(self):
import sys
l = []
diff --git a/pypy/jit/backend/arm/test/test_zrpy_gc.py b/pypy/jit/backend/arm/test/test_zrpy_gc.py
--- a/pypy/jit/backend/arm/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/arm/test/test_zrpy_gc.py
@@ -524,8 +524,8 @@
glob = A()
def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
a = A()
- glob.v = virtual_ref(a)
- virtual_ref_finish(a)
+ glob.v = vref = virtual_ref(a)
+ virtual_ref_finish(vref, a)
n -= 1
return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
return None, f, None
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -209,7 +209,7 @@
llimpl.compile_add_fail_arg(c, var2index[box])
else:
llimpl.compile_add_fail_arg(c, -1)
-
+
x = op.result
if x is not None:
if isinstance(x, history.BoxInt):
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -143,11 +143,11 @@
STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed],
lltype.Void))
def insert_stack_check():
- startaddr = rstack._stack_get_start_adr()
- length = rstack._stack_get_length()
+ endaddr = rstack._stack_get_end_adr()
+ lengthaddr = rstack._stack_get_length_adr()
f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath)
slowpathaddr = rffi.cast(lltype.Signed, f)
- return startaddr, length, slowpathaddr
+ return endaddr, lengthaddr, slowpathaddr
self.pos_exception = pos_exception
self.pos_exc_value = pos_exc_value
diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -221,18 +221,6 @@
del self.reg_bindings[var]
self.free_regs.append(loc)
except KeyError:
- if not we_are_translated():
- import pdb; pdb.set_trace()
- else:
- raise ValueError
-
- def force_spill_var(self, var):
- self._sync_var(var)
- try:
- loc = self.reg_bindings[var]
- del self.reg_bindings[var]
- self.free_regs.append(loc)
- except KeyError:
pass # 'var' is already not in a register
def loc(self, box):
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
@@ -137,10 +137,11 @@
self.current_clt = looptoken.compiled_loop_token
self.pending_guard_tokens = []
self.mc = codebuf.MachineCodeBlockWrapper()
- if self.datablockwrapper is None:
- allblocks = self.get_asmmemmgr_blocks(looptoken)
- self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr,
- allblocks)
+ #assert self.datablockwrapper is None --- but obscure case
+ # possible, e.g. getting MemoryError and continuing
+ allblocks = self.get_asmmemmgr_blocks(looptoken)
+ self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr,
+ allblocks)
def teardown(self):
self.pending_guard_tokens = None
@@ -620,11 +621,11 @@
if self.stack_check_slowpath == 0:
pass # no stack check (e.g. not translated)
else:
- startaddr, length, _ = self.cpu.insert_stack_check()
- self.mc.MOV(eax, esp) # MOV eax, current
- self.mc.SUB(eax, heap(startaddr)) # SUB eax, [startaddr]
- self.mc.CMP(eax, imm(length)) # CMP eax, length
- self.mc.J_il8(rx86.Conditions['B'], 0) # JB .skip
+ endaddr, lengthaddr, _ = self.cpu.insert_stack_check()
+ self.mc.MOV(eax, heap(endaddr)) # MOV eax, [start]
+ self.mc.SUB(eax, esp) # SUB eax, current
+ self.mc.CMP(eax, heap(lengthaddr)) # CMP eax, [length]
+ self.mc.J_il8(rx86.Conditions['BE'], 0) # JBE .skip
jb_location = self.mc.get_relative_pos()
self.mc.CALL(imm(self.stack_check_slowpath))# CALL slowpath
# patch the JB above # .skip:
@@ -678,27 +679,29 @@
nonfloatlocs, floatlocs = arglocs
self._call_header_with_stack_check()
self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth))
- for i in range(len(nonfloatlocs)):
- loc = nonfloatlocs[i]
- if isinstance(loc, RegLoc):
- assert not loc.is_xmm
- self.mc.MOV_rb(loc.value, (2 + i) * WORD)
- loc = floatlocs[i]
- if isinstance(loc, RegLoc):
- assert loc.is_xmm
- self.mc.MOVSD_xb(loc.value, (1 + i) * 2 * WORD)
+ offset = 2 * WORD
tmp = eax
xmmtmp = xmm0
for i in range(len(nonfloatlocs)):
loc = nonfloatlocs[i]
- if loc is not None and not isinstance(loc, RegLoc):
- self.mc.MOV_rb(tmp.value, (2 + i) * WORD)
- self.mc.MOV(loc, tmp)
+ if loc is not None:
+ if isinstance(loc, RegLoc):
+ assert not loc.is_xmm
+ self.mc.MOV_rb(loc.value, offset)
+ else:
+ self.mc.MOV_rb(tmp.value, offset)
+ self.mc.MOV(loc, tmp)
+ offset += WORD
loc = floatlocs[i]
- if loc is not None and not isinstance(loc, RegLoc):
- self.mc.MOVSD_xb(xmmtmp.value, (1 + i) * 2 * WORD)
- assert isinstance(loc, StackLoc)
- self.mc.MOVSD_bx(loc.value, xmmtmp.value)
+ if loc is not None:
+ if isinstance(loc, RegLoc):
+ assert loc.is_xmm
+ self.mc.MOVSD_xb(loc.value, offset)
+ else:
+ self.mc.MOVSD_xb(xmmtmp.value, offset)
+ assert isinstance(loc, StackLoc)
+ self.mc.MOVSD_bx(loc.value, xmmtmp.value)
+ offset += 2 * WORD
endpos = self.mc.get_relative_pos() + 5
self.mc.JMP_l(jmppos - endpos)
assert endpos == self.mc.get_relative_pos()
@@ -1099,6 +1102,8 @@
self.mc.MOV_bi(FORCE_INDEX_OFS, force_index)
return force_index
else:
+ # the return value is ignored, apart from the fact that it
+ # is not negative.
return 0
genop_int_neg = _unaryop("NEG")
@@ -2182,7 +2187,8 @@
# a no-op.
# reserve room for the argument to the real malloc and the
- # 8 saved XMM regs
+ # saved XMM regs (on 32 bit: 8 * 2 words; on 64 bit: 16 * 1
+ # word)
self._regalloc.reserve_param(1+16)
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -326,7 +326,7 @@
if not we_are_translated():
self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
self.assembler.regalloc_perform_llong(op, arglocs, result_loc)
-
+
def PerformMath(self, op, arglocs, result_loc):
if not we_are_translated():
self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
@@ -634,7 +634,7 @@
loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(0))
self.Perform(op, [loc0], loc0)
self.xrm.possibly_free_var(op.getarg(0))
-
+
consider_float_neg = _consider_float_unary_op
consider_float_abs = _consider_float_unary_op
@@ -722,7 +722,7 @@
loc1 = self.rm.make_sure_var_in_reg(op.getarg(1))
self.PerformLLong(op, [loc1], loc0)
self.rm.possibly_free_vars_for_op(op)
-
+
def _consider_math_sqrt(self, op):
loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(1))
self.PerformMath(op, [loc0], loc0)
@@ -1229,12 +1229,12 @@
xmmtmploc = self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp)
# Part about non-floats
# XXX we don't need a copy, we only just the original list
- src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs())
+ src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs())
if op.getarg(i).type != FLOAT]
assert tmploc not in nonfloatlocs
dst_locations1 = [loc for loc in nonfloatlocs if loc is not None]
# Part about floats
- src_locations2 = [self.loc(op.getarg(i)) for i in range(op.numargs())
+ src_locations2 = [self.loc(op.getarg(i)) for i in range(op.numargs())
if op.getarg(i).type == FLOAT]
dst_locations2 = [loc for loc in floatlocs if loc is not None]
remap_frame_layout_mixed(assembler,
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
@@ -508,7 +508,9 @@
LEA = _binaryop('LEA')
MOVSD = _binaryop('MOVSD')
+ MOVAPD = _binaryop('MOVAPD')
ADDSD = _binaryop('ADDSD')
+ ADDPD = _binaryop('ADDPD')
SUBSD = _binaryop('SUBSD')
MULSD = _binaryop('MULSD')
DIVSD = _binaryop('DIVSD')
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
@@ -690,12 +690,17 @@
define_modrm_modes('MOVSD_x*', ['\xF2', rex_nw, '\x0F\x10', register(1,8)], regtype='XMM')
define_modrm_modes('MOVSD_*x', ['\xF2', rex_nw, '\x0F\x11', register(2,8)], regtype='XMM')
+define_modrm_modes('MOVAPD_x*', ['\x66', rex_nw, '\x0F\x28', register(1,8)],
+ regtype='XMM')
+define_modrm_modes('MOVAPD_*x', ['\x66', rex_nw, '\x0F\x29', register(2,8)],
+ regtype='XMM')
define_modrm_modes('SQRTSD_x*', ['\xF2', rex_nw, '\x0F\x51', register(1,8)], regtype='XMM')
#define_modrm_modes('XCHG_r*', [rex_w, '\x87', register(1, 8)])
define_modrm_modes('ADDSD_x*', ['\xF2', rex_nw, '\x0F\x58', register(1, 8)], regtype='XMM')
+define_modrm_modes('ADDPD_x*', ['\x66', rex_nw, '\x0F\x58', register(1, 8)], regtype='XMM')
define_modrm_modes('SUBSD_x*', ['\xF2', rex_nw, '\x0F\x5C', register(1, 8)], regtype='XMM')
define_modrm_modes('MULSD_x*', ['\xF2', rex_nw, '\x0F\x59', register(1, 8)], regtype='XMM')
define_modrm_modes('DIVSD_x*', ['\xF2', rex_nw, '\x0F\x5E', register(1, 8)], regtype='XMM')
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
@@ -525,8 +525,8 @@
glob = A()
def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
a = A()
- glob.v = virtual_ref(a)
- virtual_ref_finish(a)
+ glob.v = vref = virtual_ref(a)
+ virtual_ref_finish(vref, a)
n -= 1
return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
return None, f, None
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
@@ -219,11 +219,10 @@
assert not NON_VOID_ARGS, ("arguments not supported for "
"loop-invariant function!")
# build the extraeffect
+ can_invalidate = self.quasiimmut_analyzer.analyze(op)
if extraeffect is None:
if self.virtualizable_analyzer.analyze(op):
extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
- elif self.quasiimmut_analyzer.analyze(op):
- extraeffect = EffectInfo.EF_CAN_INVALIDATE
elif loopinvariant:
extraeffect = EffectInfo.EF_LOOPINVARIANT
elif pure:
@@ -236,12 +235,14 @@
#
effectinfo = effectinfo_from_writeanalyze(
self.readwrite_analyzer.analyze(op), self.cpu, extraeffect,
- oopspecindex)
+ oopspecindex, can_invalidate)
#
if pure or loopinvariant:
assert effectinfo is not None
assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
- assert extraeffect != EffectInfo.EF_CAN_INVALIDATE
+ # XXX this should also say assert not can_invalidate, but
+ # it can't because our analyzer is not good enough for now
+ # (and getexecutioncontext() can't really invalidate)
#
return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT,
effectinfo)
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
@@ -13,7 +13,6 @@
EF_LOOPINVARIANT = 1 #special: call it only once per loop
EF_CANNOT_RAISE = 2 #a function which cannot raise
EF_CAN_RAISE = 3 #normal function (can raise)
- EF_CAN_INVALIDATE = 4 #can force all GUARD_NOT_INVALIDATED
EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables
# the 'oopspecindex' field is one of the following values:
@@ -79,7 +78,8 @@
def __new__(cls, readonly_descrs_fields,
write_descrs_fields, write_descrs_arrays,
extraeffect=EF_CAN_RAISE,
- oopspecindex=OS_NONE):
+ oopspecindex=OS_NONE,
+ can_invalidate=False):
key = (frozenset(readonly_descrs_fields),
frozenset(write_descrs_fields),
frozenset(write_descrs_arrays),
@@ -97,19 +97,21 @@
result.write_descrs_fields = write_descrs_fields
result.write_descrs_arrays = write_descrs_arrays
result.extraeffect = extraeffect
+ result.can_invalidate = can_invalidate
result.oopspecindex = oopspecindex
cls._cache[key] = result
return result
def check_can_invalidate(self):
- return self.extraeffect >= self.EF_CAN_INVALIDATE
+ return self.can_invalidate
def check_forces_virtual_or_virtualizable(self):
return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
def effectinfo_from_writeanalyze(effects, cpu,
extraeffect=EffectInfo.EF_CAN_RAISE,
- oopspecindex=EffectInfo.OS_NONE):
+ oopspecindex=EffectInfo.OS_NONE,
+ can_invalidate=False):
from pypy.translator.backendopt.writeanalyze import top_set
if effects is top_set:
return None
@@ -147,7 +149,8 @@
write_descrs_fields,
write_descrs_arrays,
extraeffect,
- oopspecindex)
+ oopspecindex,
+ can_invalidate)
def consider_struct(TYPE, fieldname):
if fieldType(TYPE, fieldname) is lltype.Void:
diff --git a/pypy/jit/codewriter/jitcode.py b/pypy/jit/codewriter/jitcode.py
--- a/pypy/jit/codewriter/jitcode.py
+++ b/pypy/jit/codewriter/jitcode.py
@@ -100,6 +100,9 @@
def __repr__(self):
return '<JitCode %r>' % self.name
+ def _clone_if_mutable(self):
+ raise NotImplementedError
+
class MissingLiveness(Exception):
pass
@@ -111,6 +114,9 @@
dict = getattr(self, 'dict', '?')
return '<SwitchDictDescr %s>' % (dict,)
+ def _clone_if_mutable(self):
+ raise NotImplementedError
+
class LiveVarsInfo(object):
def __init__(self, live_i, live_r, live_f):
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
@@ -209,7 +209,6 @@
def rewrite_op_cast_int_to_unichar(self, op): pass
def rewrite_op_cast_int_to_uint(self, op): pass
def rewrite_op_cast_uint_to_int(self, op): pass
- def rewrite_op_resume_point(self, op): pass
def _rewrite_symmetric(self, op):
"""Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating
diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py
--- a/pypy/jit/codewriter/policy.py
+++ b/pypy/jit/codewriter/policy.py
@@ -63,12 +63,27 @@
contains_loop = contains_loop and not getattr(
func, '_jit_unroll_safe_', False)
- res = see_function and not contains_unsupported_variable_type(graph,
- self.supports_floats,
- self.supports_longlong)
+ unsupported = contains_unsupported_variable_type(graph,
+ self.supports_floats,
+ self.supports_longlong)
+ res = see_function and not unsupported
if res and contains_loop:
self.unsafe_loopy_graphs.add(graph)
- return res and not contains_loop
+ res = res and not contains_loop
+ if (see_function and not res and
+ getattr(graph, "access_directly", False)):
+ # This happens when we have a function which has an argument with
+ # the access_directly flag, and the annotator has determined we will
+ # see the function. (See
+ # pypy/annotation/specialize.py:default_specialize) However,
+ # look_inside_graph just decided that we will not see it. (It has a
+ # loop or unsupported variables.) If we return False, the call will
+ # be turned into a residual call, but the graph is access_directly!
+ # If such a function is called and accesses a virtualizable, the JIT
+ # will not notice, and the virtualizable will fall out of sync. So,
+ # we fail loudly now.
+ raise ValueError("access_directly on a function which we don't see %s" % graph)
+ return res
def contains_unsupported_variable_type(graph, supports_floats,
supports_longlong):
diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py
--- a/pypy/jit/codewriter/test/test_policy.py
+++ b/pypy/jit/codewriter/test/test_policy.py
@@ -1,4 +1,5 @@
import sys
+import py
from pypy.jit.codewriter.policy import contains_unsupported_variable_type
from pypy.jit.codewriter.policy import JitPolicy
from pypy.jit.codewriter import support
@@ -107,3 +108,19 @@
mod = called_graph.func.__module__
assert (mod == 'pypy.rpython.rlist' or
mod == 'pypy.rpython.lltypesystem.rlist')
+
+def test_access_directly_but_not_seen():
+ class X:
+ _virtualizable2_ = ["a"]
+ def h(x, y):
+ w = 0
+ for i in range(y):
+ w += 4
+ return w
+ def f(y):
+ x = jit.hint(X(), access_directly=True)
+ h(x, y)
+ rtyper = support.annotate(f, [3])
+ h_graph = rtyper.annotator.translator.graphs[1]
+ assert h_graph.func is h
+ py.test.raises(ValueError, JitPolicy().look_inside_graph, h_graph)
diff --git a/pypy/jit/conftest.py b/pypy/jit/conftest.py
--- a/pypy/jit/conftest.py
+++ b/pypy/jit/conftest.py
@@ -5,7 +5,4 @@
group.addoption('--slow', action="store_true",
default=False, dest="run_slow_tests",
help="run all the compiled tests (instead of just a few)")
- group.addoption('--viewloops', action="store_true",
- default=False, dest="viewloops",
- help="show only the compiled loops")
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -97,7 +97,7 @@
history = metainterp.history
loop = create_empty_loop(metainterp)
- loop.inputargs = history.inputargs
+ loop.inputargs = history.inputargs[:]
for box in loop.inputargs:
assert isinstance(box, Box)
# make a copy, because optimize_loop can mutate the ops and descrs
@@ -124,18 +124,21 @@
return old_loop_token
if loop.preamble.operations is not None:
- send_loop_to_backend(metainterp_sd, loop, "loop")
+ send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop,
+ "loop")
record_loop_or_bridge(metainterp_sd, loop)
token = loop.preamble.token
if full_preamble_needed:
- send_loop_to_backend(metainterp_sd, loop.preamble, "entry bridge")
+ send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd,
+ loop.preamble, "entry bridge")
insert_loop_token(old_loop_tokens, loop.preamble.token)
jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
greenkey, loop.preamble.token)
record_loop_or_bridge(metainterp_sd, loop.preamble)
return token
else:
- send_loop_to_backend(metainterp_sd, loop, "loop")
+ send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop,
+ "loop")
insert_loop_token(old_loop_tokens, loop_token)
jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
greenkey, loop.token)
@@ -150,7 +153,9 @@
# XXX do we still need a list?
old_loop_tokens.append(loop_token)
-def send_loop_to_backend(metainterp_sd, loop, type):
+def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type):
+ jitdriver_sd.on_compile(metainterp_sd.logger_ops, loop.token,
+ loop.operations, type, greenkey)
globaldata = metainterp_sd.globaldata
loop_token = loop.token
loop_token.number = n = globaldata.loopnumbering
@@ -186,8 +191,11 @@
if metainterp_sd.warmrunnerdesc is not None: # for tests
metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token)
-def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations,
- original_loop_token):
+def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs,
+ operations, original_loop_token):
+ n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
+ jitdriver_sd.on_compile_bridge(metainterp_sd.logger_ops,
+ original_loop_token, operations, n)
if not we_are_translated():
show_loop(metainterp_sd)
TreeLoop.check_consistency_of(inputargs, operations)
@@ -204,7 +212,6 @@
metainterp_sd.stats.compiled()
metainterp_sd.log("compiled new bridge")
#
- n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset)
#
if metainterp_sd.warmrunnerdesc is not None: # for tests
@@ -390,8 +397,9 @@
inputargs = metainterp.history.inputargs
if not we_are_translated():
self._debug_suboperations = new_loop.operations
- send_bridge_to_backend(metainterp.staticdata, self, inputargs,
- new_loop.operations, new_loop.token)
+ send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
+ self, inputargs, new_loop.operations,
+ new_loop.token)
def copy_all_attributes_into(self, res):
# XXX a bit ugly to have to list them all here
@@ -570,7 +578,8 @@
# to every guard in the loop.
new_loop_token = make_loop_token(len(redargs), jitdriver_sd)
new_loop.token = new_loop_token
- send_loop_to_backend(metainterp_sd, new_loop, "entry bridge")
+ send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd,
+ metainterp_sd, new_loop, "entry bridge")
# send the new_loop to warmspot.py, to be called directly the next time
jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
self.original_greenkey,
@@ -600,7 +609,7 @@
# Attempt to use optimize_bridge(). This may return None in case
# it does not work -- i.e. none of the existing old_loop_tokens match.
new_loop = create_empty_loop(metainterp)
- new_loop.inputargs = metainterp.history.inputargs
+ new_loop.inputargs = metainterp.history.inputargs[:]
# clone ops, as optimize_bridge can mutate the ops
new_loop.operations = [op.clone() for op in metainterp.history.operations]
metainterp_sd = metainterp.staticdata
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -294,8 +294,8 @@
cpu.set_future_value_int(j, self.value)
def same_constant(self, other):
- if isinstance(other, Const):
- return self.value == other.getint()
+ if isinstance(other, ConstInt):
+ return self.value == other.value
return False
def nonnull(self):
@@ -787,7 +787,6 @@
def dump(self):
self.compiled_loop_token.cpu.dump_loop_token(self)
-
class TreeLoop(object):
inputargs = None
operations = None
@@ -957,7 +956,7 @@
compiled_count = 0
enter_count = 0
aborted_count = 0
- history = None
+ operations = None
def __init__(self):
self.loops = []
@@ -965,7 +964,7 @@
self.aborted_keys = []
def set_history(self, history):
- self.history = history
+ self.operations = history.operations
def aborted(self):
self.aborted_count += 1
@@ -995,7 +994,7 @@
def check_history(self, expected=None, **check):
insns = {}
- for op in self.history.operations:
+ for op in self.operations:
opname = op.getopname()
insns[opname] = insns.get(opname, 0) + 1
if expected is not None:
diff --git a/pypy/jit/metainterp/jitdriver.py b/pypy/jit/metainterp/jitdriver.py
--- a/pypy/jit/metainterp/jitdriver.py
+++ b/pypy/jit/metainterp/jitdriver.py
@@ -20,6 +20,7 @@
# self.portal_finishtoken... pypy.jit.metainterp.pyjitpl
# self.index ... pypy.jit.codewriter.call
# self.mainjitcode ... pypy.jit.codewriter.call
+ # self.on_compile ... pypy.jit.metainterp.warmstate
# These attributes are read by the backend in CALL_ASSEMBLER:
# self.assembler_helper_adr
diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py
--- a/pypy/jit/metainterp/logger.py
+++ b/pypy/jit/metainterp/logger.py
@@ -75,6 +75,40 @@
else:
return '?'
+ def repr_of_resop(self, memo, op, ops_offset=None):
+ if op.getopnum() == rop.DEBUG_MERGE_POINT:
+ loc = op.getarg(0)._get_str()
+ reclev = op.getarg(1).getint()
+ return "debug_merge_point('%s', %s)" % (loc, reclev)
+ if ops_offset is None:
+ offset = -1
+ else:
+ offset = ops_offset.get(op, -1)
+ if offset == -1:
+ s_offset = ""
+ else:
+ s_offset = "+%d: " % offset
+ args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())])
+ if op.result is not None:
+ res = self.repr_of_arg(memo, op.result) + " = "
+ else:
+ res = ""
+ is_guard = op.is_guard()
+ if op.getdescr() is not None:
+ descr = op.getdescr()
+ if is_guard and self.guard_number:
+ index = self.metainterp_sd.cpu.get_fail_descr_number(descr)
+ r = "<Guard%d>" % index
+ else:
+ r = self.repr_of_descr(descr)
+ args += ', descr=' + r
+ if is_guard and op.getfailargs() is not None:
+ fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg)
+ for arg in op.getfailargs()]) + ']'
+ else:
+ fail_args = ''
+ return s_offset + res + op.getopname() + '(' + args + ')' + fail_args
+
def _log_operations(self, inputargs, operations, ops_offset):
if not have_debug_prints():
return
@@ -86,37 +120,7 @@
debug_print('[' + args + ']')
for i in range(len(operations)):
op = operations[i]
- if op.getopnum() == rop.DEBUG_MERGE_POINT:
- loc = op.getarg(0)._get_str()
- reclev = op.getarg(1).getint()
- debug_print("debug_merge_point('%s', %s)" % (loc, reclev))
- continue
- offset = ops_offset.get(op, -1)
- if offset == -1:
- s_offset = ""
- else:
- s_offset = "+%d: " % offset
- args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())])
- if op.result is not None:
- res = self.repr_of_arg(memo, op.result) + " = "
- else:
- res = ""
- is_guard = op.is_guard()
- if op.getdescr() is not None:
- descr = op.getdescr()
- if is_guard and self.guard_number:
- index = self.metainterp_sd.cpu.get_fail_descr_number(descr)
- r = "<Guard%d>" % index
- else:
- r = self.repr_of_descr(descr)
- args += ', descr=' + r
- if is_guard and op.getfailargs() is not None:
- fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg)
- for arg in op.getfailargs()]) + ']'
- else:
- fail_args = ''
- debug_print(s_offset + res + op.getopname() +
- '(' + args + ')' + fail_args)
+ debug_print(self.repr_of_resop(memo, operations[i], ops_offset))
if ops_offset and None in ops_offset:
offset = ops_offset[None]
debug_print("+%d: --end of the loop--" % offset)
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
@@ -161,6 +161,9 @@
if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
# Synthesize the non overflowing op for optimize_default to reuse
self.pure(rop.INT_ADD, op.getarglist()[:], op.result)
+ # Synthesize the reverse op for optimize_default to reuse
+ self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0))
+ self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1))
def optimize_INT_SUB_OVF(self, op):
@@ -180,6 +183,10 @@
if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
# Synthesize the non overflowing op for optimize_default to reuse
self.pure(rop.INT_SUB, op.getarglist()[:], op.result)
+ # Synthesize the reverse ops for optimize_default to reuse
+ self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0))
+ self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1))
+
def optimize_INT_MUL_OVF(self, op):
v1 = self.getvalue(op.getarg(0))
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
@@ -415,14 +415,22 @@
dest_start_box = self.get_constant_box(op.getarg(4))
length = self.get_constant_box(op.getarg(5))
if (source_value.is_virtual() and source_start_box and dest_start_box
- and length and dest_value.is_virtual()):
- # XXX optimize the case where dest value is not virtual,
- # but we still can avoid a mess
+ and length and (dest_value.is_virtual() or length.getint() <= 8)):
+ from pypy.jit.metainterp.optimizeopt.virtualize import VArrayValue
+ assert isinstance(source_value, VArrayValue)
source_start = source_start_box.getint()
dest_start = dest_start_box.getint()
for index in range(length.getint()):
val = source_value.getitem(index + source_start)
- dest_value.setitem(index + dest_start, val)
+ if dest_value.is_virtual():
+ dest_value.setitem(index + dest_start, val)
+ else:
+ newop = ResOperation(rop.SETARRAYITEM_GC,
+ [op.getarg(2),
+ ConstInt(index + dest_start),
+ val.force_box()], None,
+ descr=source_value.arraydescr)
+ self.emit_operation(newop)
return True
if length and length.getint() == 0:
return True # 0-length arraycopy
@@ -432,6 +440,9 @@
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
+ if v2.is_constant() and v2.box.getint() == 1:
+ self.make_equal_to(op.result, v1)
+ return
if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant():
val = v2.box.getint()
if val & (val - 1) == 0 and val > 0: # val == 2**shift
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
@@ -330,18 +330,28 @@
vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
def optimize_VIRTUAL_REF_FINISH(self, op):
- # Set the 'forced' field of the virtual_ref.
- # In good cases, this is all virtual, so has no effect.
- # Otherwise, this forces the real object -- but only now, as
- # opposed to much earlier. This is important because the object is
- # typically a PyPy PyFrame, and now is the end of its execution, so
- # forcing it now does not have catastrophic effects.
+ # This operation is used in two cases. In normal cases, it
+ # is the end of the frame, and op.getarg(1) is NULL. In this
+ # case we just clear the vref.virtual_token, because it contains
+ # a stack frame address and we are about to leave the frame.
+ # In that case vref.forced should still be NULL, and remains
+ # NULL; and accessing the frame through the vref later is
+ # *forbidden* and will raise InvalidVirtualRef.
+ #
+ # In the other (uncommon) case, the operation is produced
+ # earlier, because the vref was forced during tracing already.
+ # In this case, op.getarg(1) is the virtual to force, and we
+ # have to store it in vref.forced.
+ #
vrefinfo = self.optimizer.metainterp_sd.virtualref_info
- # op.getarg(1) should really never point to null here
+ seo = self.optimizer.send_extra_operation
+
# - set 'forced' to point to the real object
- seo = self.optimizer.send_extra_operation
- seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None,
- descr = vrefinfo.descr_forced))
+ objbox = op.getarg(1)
+ if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox):
+ seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None,
+ descr = vrefinfo.descr_forced))
+
# - set 'virtual_token' to TOKEN_NONE
args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)]
seo(ResOperation(rop.SETFIELD_GC, args, None,
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
@@ -4,7 +4,7 @@
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import debug_start, debug_stop, debug_print
from pypy.rlib.debug import make_sure_not_resized
-from pypy.rlib import nonconst
+from pypy.rlib import nonconst, rstack
from pypy.jit.metainterp import history, compile, resume
from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
@@ -867,7 +867,6 @@
any_operation = len(self.metainterp.history.operations) > 0
jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
self.verify_green_args(jitdriver_sd, greenboxes)
- # xxx we may disable the following line in some context later
self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion,
greenboxes)
@@ -1049,8 +1048,10 @@
vrefinfo = metainterp.staticdata.virtualref_info
vref = vrefbox.getref_base()
if vrefinfo.is_virtual_ref(vref):
+ # XXX write a comment about nullbox
+ nullbox = self.metainterp.cpu.ts.CONST_NULL
metainterp.history.record(rop.VIRTUAL_REF_FINISH,
- [vrefbox, lastbox], None)
+ [vrefbox, nullbox], None)
@arguments()
def opimpl_ll_read_timestamp(self):
@@ -1844,9 +1845,9 @@
else:
self.compile(original_boxes, live_arg_boxes, start, resumedescr)
# creation of the loop was cancelled!
- #self.staticdata.log('cancelled, tracing more...')
- self.staticdata.log('cancelled, stopping tracing')
- raise SwitchToBlackhole(ABORT_BAD_LOOP)
+ self.staticdata.log('cancelled, tracing more...')
+ #self.staticdata.log('cancelled, stopping tracing')
+ #raise SwitchToBlackhole(ABORT_BAD_LOOP)
# Otherwise, no loop found so far, so continue tracing.
start = len(self.history.operations)
@@ -1911,6 +1912,7 @@
def compile(self, original_boxes, live_arg_boxes, start, start_resumedescr):
num_green_args = self.jitdriver_sd.num_green_args
+ original_inputargs = self.history.inputargs
self.history.inputargs = original_boxes[num_green_args:]
greenkey = original_boxes[:num_green_args]
old_loop_tokens = self.get_compiled_merge_points(greenkey)
@@ -1919,7 +1921,11 @@
greenkey, start, start_resumedescr)
if loop_token is not None: # raise if it *worked* correctly
self.set_compiled_merge_points(greenkey, old_loop_tokens)
+ self.history.inputargs = None
+ self.history.operations = None
raise GenerateMergePoint(live_arg_boxes, loop_token)
+
+ self.history.inputargs = original_inputargs
self.history.operations.pop() # remove the JUMP
# FIXME: Why is self.history.inputargs not restored?
@@ -1936,10 +1942,12 @@
target_loop_token = compile.compile_new_bridge(self,
old_loop_tokens,
self.resumekey)
- if target_loop_token is not None: # raise if it *worked* correctly
- raise GenerateMergePoint(live_arg_boxes, target_loop_token)
finally:
self.history.operations.pop() # remove the JUMP
+ if target_loop_token is not None: # raise if it *worked* correctly
+ self.history.inputargs = None
+ self.history.operations = None
+ raise GenerateMergePoint(live_arg_boxes, target_loop_token)
def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
bridge_arg_boxes, start_resumedescr):
@@ -1974,7 +1982,8 @@
assert False
assert target_loop_token is not None
- self.history.operations = original_operations
+ self.history.inputargs = None
+ self.history.operations = None
raise GenerateMergePoint(live_arg_boxes, old_loop_tokens[0])
def compile_done_with_this_frame(self, exitbox):
@@ -2044,10 +2053,16 @@
def initialize_state_from_guard_failure(self, resumedescr):
# guard failure: rebuild a complete MIFrame stack
- self.in_recursion = -1 # always one portal around
- self.history = history.History()
- inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
- self.history.inputargs = [box for box in inputargs_and_holes if box]
+ # This is stack-critical code: it must not be interrupted by StackOverflow,
+ # otherwise the jit_virtual_refs are left in a dangling state.
+ rstack._stack_criticalcode_start()
+ try:
+ self.in_recursion = -1 # always one portal around
+ self.history = history.History()
+ inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
+ self.history.inputargs = [box for box in inputargs_and_holes if box]
+ finally:
+ rstack._stack_criticalcode_stop()
def initialize_virtualizable(self, original_boxes):
vinfo = self.jitdriver_sd.virtualizable_info
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -6,7 +6,7 @@
from pypy.jit.metainterp import jitprof
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
-from pypy.rlib import rarithmetic
+from pypy.rlib import rarithmetic, rstack
from pypy.rlib.objectmodel import we_are_translated, specialize
from pypy.rlib.debug import have_debug_prints, ll_assert
from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -978,12 +978,18 @@
def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
all_virtuals=None):
- resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
- storage, all_virtuals)
- vinfo = jitdriver_sd.virtualizable_info
- ginfo = jitdriver_sd.greenfield_info
- vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
- resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
+ # The initialization is stack-critical code: it must not be interrupted by
+ # StackOverflow, otherwise the jit_virtual_refs are left in a dangling state.
+ rstack._stack_criticalcode_start()
+ try:
+ resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
+ storage, all_virtuals)
+ vinfo = jitdriver_sd.virtualizable_info
+ ginfo = jitdriver_sd.greenfield_info
+ vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
+ resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
+ finally:
+ rstack._stack_criticalcode_stop()
#
# First get a chain of blackhole interpreters whose length is given
# by the depth of rd_frame_info_list. The first one we get must be
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -26,6 +26,10 @@
def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
pass
+ def helper_func(self, FUNCPTR, func):
+ from pypy.rpython.annlowlevel import llhelper
+ return llhelper(FUNCPTR, func)
+
def jit_cell_at_key(self, greenkey):
assert greenkey == []
return self._cell
@@ -37,6 +41,7 @@
func._jit_unroll_safe_ = True
rtyper = support.annotate(func, values, type_system=type_system)
graphs = rtyper.annotator.translator.graphs
+ testself.all_graphs = graphs
result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
class FakeJitDriverSD:
@@ -46,6 +51,8 @@
greenfield_info = None
result_type = result_kind
portal_runner_ptr = "???"
+ on_compile = lambda *args: None
+ on_compile_bridge = lambda *args: None
stats = history.Stats()
cpu = CPUClass(rtyper, stats, None, False)
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
@@ -1864,7 +1864,7 @@
return a1.val + b1.val
res = self.meta_interp(g, [3, 23])
assert res == 7068153
- self.check_loop_count(6)
+ self.check_loop_count(7)
self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
guard_false=2)
@@ -2101,6 +2101,79 @@
assert self.meta_interp(f, [5, 100]) == 0
self.check_loops(int_rshift=1, everywhere=True)
+ def test_inputarg_reset_bug(self):
+ ## j = 0
+ ## while j < 100:
+ ## j += 1
+
+ ## c = 0
+ ## j = 0
+ ## while j < 2:
+ ## j += 1
+ ## if c == 0:
+ ## c = 1
+ ## else:
+ ## c = 0
+
+ ## j = 0
+ ## while j < 100:
+ ## j += 1
+
+ def get_printable_location(i):
+ return str(i)
+
+ myjitdriver = JitDriver(greens = ['i'], reds = ['j', 'c', 'a'],
+ get_printable_location=get_printable_location)
+ bytecode = "0j10jc20a3"
+ def f():
+ myjitdriver.set_param('threshold', 7)
+ myjitdriver.set_param('trace_eagerness', 1)
+ i = j = c = a = 1
+ while True:
+ myjitdriver.jit_merge_point(i=i, j=j, c=c, a=a)
+ if i >= len(bytecode):
+ break
+ op = bytecode[i]
+ if op == 'j':
+ j += 1
+ elif op == 'c':
+ c = hint(c, promote=True)
+ c = 1 - c
+ elif op == '2':
+ if j < 3:
+ i -= 3
+ myjitdriver.can_enter_jit(i=i, j=j, c=c, a=a)
+ elif op == '1':
+ k = j*a
+ if j < 100:
+ i -= 2
+ a += k
+ myjitdriver.can_enter_jit(i=i, j=j, c=c, a=a)
+ else:
+ a += k*2
+ elif op == '0':
+ j = c = a = 0
+ elif op == 'a':
+ j += 1
+ a += 1
+ elif op == '3':
+ if a < 100:
+ i -= 2
+ myjitdriver.can_enter_jit(i=i, j=j, c=c, a=a)
+
+ else:
+ return ord(op)
+ i += 1
+ return 42
+ assert f() == 42
+ def g():
+ res = 1
+ for i in range(10):
+ res = f()
+ return res
+ res = self.meta_interp(g, [])
+ assert res == 42
+
def test_read_timestamp(self):
import time
from pypy.rlib.rtimer import read_timestamp
diff --git a/pypy/jit/metainterp/test/test_history.py b/pypy/jit/metainterp/test/test_history.py
--- a/pypy/jit/metainterp/test/test_history.py
+++ b/pypy/jit/metainterp/test/test_history.py
@@ -9,3 +9,20 @@
s = lltype.cast_pointer(lltype.Ptr(S), t)
const = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))
assert const._getrepr_() == "*T"
+
+def test_same_constant():
+ c1a = ConstInt(0)
+ c1b = ConstInt(0)
+ c2a = ConstPtr(lltype.nullptr(llmemory.GCREF.TO))
+ c2b = ConstPtr(lltype.nullptr(llmemory.GCREF.TO))
+ c3a = Const._new(0.0)
+ c3b = Const._new(0.0)
+ assert c1a.same_constant(c1b)
+ assert not c1a.same_constant(c2b)
+ assert not c1a.same_constant(c3b)
+ assert not c2a.same_constant(c1b)
+ assert c2a.same_constant(c2b)
+ assert not c2a.same_constant(c3b)
+ assert not c3a.same_constant(c1b)
+ assert not c3a.same_constant(c2b)
+ assert c3a.same_constant(c3b)
diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py
--- a/pypy/jit/metainterp/test/test_jitdriver.py
+++ b/pypy/jit/metainterp/test/test_jitdriver.py
@@ -10,8 +10,59 @@
def getloc2(g):
return "in jitdriver2, with g=%d" % g
+class JitDriverTests(object):
+ def test_on_compile(self):
+ called = {}
+
+ class MyJitDriver(JitDriver):
+ def on_compile(self, logger, looptoken, operations, type, n, m):
+ called[(m, n, type)] = looptoken
-class MultipleJitDriversTests:
+ driver = MyJitDriver(greens = ['n', 'm'], reds = ['i'])
+
+ def loop(n, m):
+ i = 0
+ while i < n + m:
+ driver.can_enter_jit(n=n, m=m, i=i)
+ driver.jit_merge_point(n=n, m=m, i=i)
+ i += 1
+
+ self.meta_interp(loop, [1, 4])
+ assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop")]
+ self.meta_interp(loop, [2, 4])
+ assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop"),
+ (4, 2, "entry bridge"), (4, 2, "loop")]
+
+ def test_on_compile_bridge(self):
+ called = {}
+
+ class MyJitDriver(JitDriver):
+ def on_compile(self, logger, looptoken, operations, type, n, m):
+ called[(m, n, type)] = loop
+ def on_compile_bridge(self, logger, orig_token, operations, n):
+ assert 'bridge' not in called
+ called['bridge'] = orig_token
+
+ driver = MyJitDriver(greens = ['n', 'm'], reds = ['i'])
+
+ def loop(n, m):
+ i = 0
+ while i < n + m:
+ driver.can_enter_jit(n=n, m=m, i=i)
+ driver.jit_merge_point(n=n, m=m, i=i)
+ if i >= 4:
+ i += 2
+ i += 1
+
+ self.meta_interp(loop, [1, 10])
+ assert sorted(called.keys()) == ['bridge', (10, 1, "entry bridge"),
+ (10, 1, "loop")]
+
+
+class TestLLtypeSingle(JitDriverTests, LLJitMixin):
+ pass
+
+class MultipleJitDriversTests(object):
def test_simple(self):
myjitdriver1 = JitDriver(greens=[], reds=['n', 'm'],
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -236,4 +236,8 @@
return a * b
res = self.meta_interp(f, [37])
assert res == f(37)
- self.check_loops(getfield_gc=1, everywhere=True)
+ # There is the one actual field on a, plus 2 getfield's from the list
+ # itself, 1 to get the length (which is then incremented and passed to
+ # the resize func), and then a read of the items field to actually
+ # perform the setarrayitem on
+ self.check_loops(getfield_gc=5, everywhere=True)
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -3402,6 +3402,56 @@
'''
self.optimize_loop(ops, expected)
+ def test_arraycopy_dest_not_virtual(self):
+ ops = '''
+ []
+ p1 = new_array(3, descr=arraydescr)
+ p2 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p1, 2, 10, descr=arraydescr)
+ setarrayitem_gc(p2, 2, 13, descr=arraydescr)
+ escape(p2)
+ call(0, p1, p2, 0, 0, 3, descr=arraycopydescr)
+ escape(p2)
+ jump()
+ '''
+ expected = '''
+ []
+ p2 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p2, 2, 13, descr=arraydescr)
+ escape(p2)
+ setarrayitem_gc(p2, 0, 0, descr=arraydescr)
+ setarrayitem_gc(p2, 1, 0, descr=arraydescr)
+ setarrayitem_gc(p2, 2, 10, descr=arraydescr)
+ escape(p2)
+ jump()
+ '''
+ self.optimize_loop(ops, expected)
+
+ def test_arraycopy_dest_not_virtual_too_long(self):
+ ops = '''
+ []
+ p1 = new_array(10, descr=arraydescr)
+ p2 = new_array(10, descr=arraydescr)
+ setarrayitem_gc(p1, 2, 10, descr=arraydescr)
+ setarrayitem_gc(p2, 2, 13, descr=arraydescr)
+ escape(p2)
+ call(0, p1, p2, 0, 0, 10, descr=arraycopydescr)
+ escape(p2)
+ jump()
+ '''
+ expected = '''
+ []
+ p2 = new_array(10, descr=arraydescr)
+ setarrayitem_gc(p2, 2, 13, descr=arraydescr)
+ escape(p2)
+ p1 = new_array(10, descr=arraydescr)
+ setarrayitem_gc(p1, 2, 10, descr=arraydescr)
+ call(0, p1, p2, 0, 0, 10, descr=arraycopydescr)
+ escape(p2)
+ jump()
+ '''
+ self.optimize_loop(ops, expected)
+
def test_bound_lt(self):
ops = """
[i0]
@@ -3900,6 +3950,50 @@
"""
self.optimize_loop(ops, expected)
+ def test_add_sub_ovf(self):
+ ops = """
+ [i1]
+ i2 = int_add_ovf(i1, 1)
+ guard_no_overflow() []
+ i3 = int_sub_ovf(i2, 1)
+ guard_no_overflow() []
+ escape(i3)
+ jump(i2)
+ """
+ expected = """
+ [i1]
+ i2 = int_add_ovf(i1, 1)
+ guard_no_overflow() []
+ escape(i1)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_add_sub_ovf_virtual_unroll(self):
+ ops = """
+ [p15]
+ i886 = getfield_gc_pure(p15, descr=valuedescr)
+ i888 = int_sub_ovf(i886, 1)
+ guard_no_overflow() []
+ escape(i888)
+ i4360 = getfield_gc_pure(p15, descr=valuedescr)
+ i4362 = int_add_ovf(i4360, 1)
+ guard_no_overflow() []
+ i4360p = int_sub_ovf(i4362, 1)
+ guard_no_overflow() []
+ p4364 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p4364, i4362, descr=valuedescr)
+ jump(p4364)
+ """
+ expected = """
+ [i0, i1]
+ escape(i1)
+ i2 = int_add_ovf(i0, 1)
+ guard_no_overflow() []
+ jump(i2, i0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_framestackdepth_overhead(self):
ops = """
[p0, i22]
@@ -4376,7 +4470,6 @@
i8 = int_floordiv(4, i2)
i9 = int_rshift(i1, 2)
i10 = int_floordiv(i1, 0)
- i11 = int_rshift(i1, 0)
i12 = int_floordiv(i2, 2)
i13 = int_floordiv(i2, 3)
i14 = int_floordiv(i2, 4)
@@ -4453,6 +4546,18 @@
"""
self.optimize_loop(ops, expected)
+ def test_int_div_1(self):
+ ops = """
+ [i0]
+ i1 = int_floordiv(i0, 1)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_subsub_ovf(self):
ops = """
[i0]
diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py
--- a/pypy/jit/metainterp/test/test_optimizeutil.py
+++ b/pypy/jit/metainterp/test/test_optimizeutil.py
@@ -133,7 +133,8 @@
EffectInfo([adescr], [], []))
mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
EffectInfo([nextdescr], [], [],
- EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE))
+ EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE,
+ can_invalidate=True))
arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY))
diff --git a/pypy/jit/metainterp/test/test_resoperation.py b/pypy/jit/metainterp/test/test_resoperation.py
--- a/pypy/jit/metainterp/test/test_resoperation.py
+++ b/pypy/jit/metainterp/test/test_resoperation.py
@@ -72,7 +72,7 @@
def test_get_deep_immutable_oplist():
ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c')]
newops = rop.get_deep_immutable_oplist(ops)
- py.test.raises(AttributeError, "newops.append('foobar')")
+ py.test.raises(TypeError, "newops.append('foobar')")
py.test.raises(TypeError, "newops[0] = 'foobar'")
py.test.raises(AssertionError, "newops[0].setarg(0, 'd')")
py.test.raises(AssertionError, "newops[0].setdescr('foobar')")
diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py
--- a/pypy/jit/metainterp/test/test_send.py
+++ b/pypy/jit/metainterp/test/test_send.py
@@ -204,7 +204,6 @@
# InvalidLoop condition, and was then unrolled, giving two copies
# of the body in a single bigger loop with no failing guard except
# the final one.
- py.test.skip('dissabled "try to trace some more when compile fails"')
self.check_loop_count(1)
self.check_loops(guard_class=0,
int_add=2, int_sub=2)
@@ -231,6 +230,7 @@
return self.y
w1 = W1(10)
w2 = W2(20)
+
def f(x, y):
if x & 1:
w = w1
@@ -246,7 +246,6 @@
assert res == f(3, 28)
res = self.meta_interp(f, [4, 28])
assert res == f(4, 28)
- py.test.skip('dissabled "try to trace some more when compile fails"')
self.check_loop_count(1)
self.check_loops(guard_class=0,
int_add=2, int_sub=2)
diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py
--- a/pypy/jit/metainterp/test/test_tl.py
+++ b/pypy/jit/metainterp/test/test_tl.py
@@ -58,7 +58,7 @@
exit:
RETURN
''')
-
+
codes = [code, code2]
def main(n, inputarg):
code = codes[n]
@@ -116,7 +116,7 @@
codes = [code, '']
def main(num, arg):
return interp(codes[num], inputarg=arg)
-
+
res = self.meta_interp(main, [0, 20], enable_opts='',
listops=listops, backendopt=True, policy=policy)
assert res == 0
@@ -128,7 +128,6 @@
from pypy.jit.tl.tl import Stack
methods = [Stack.put,
Stack.pick,
- Stack.roll,
Stack.append,
Stack.pop]
for meth in methods:
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -1,9 +1,10 @@
import py
from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
+from pypy.rpython.llinterp import LLException
from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
-from pypy.rlib.jit import virtual_ref, virtual_ref_finish
+from pypy.rlib.jit import virtual_ref, virtual_ref_finish, InvalidVirtualRef
from pypy.rlib.objectmodel import compute_unique_id
-from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, _get_jitcodes
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.virtualref import VirtualRefInfo
@@ -16,6 +17,29 @@
self.vrefinfo = VirtualRefInfo(self.warmrunnerstate)
self.cw.setup_vrefinfo(self.vrefinfo)
+ def test_rewrite_graphs(self):
+ class X:
+ pass
+ def fn():
+ x = X()
+ vref = virtual_ref(x)
+ x1 = vref() # jit_force_virtual
+ virtual_ref_finish(vref, x)
+ #
+ _get_jitcodes(self, self.CPUClass, fn, [], self.type_system)
+ graph = self.all_graphs[0]
+ assert graph.name == 'fn'
+ self.vrefinfo.replace_force_virtual_with_call([graph])
+ #
+ def check_call(op, fname):
+ assert op.opname == 'direct_call'
+ assert op.args[0].value._obj._name == fname
+ #
+ ops = [op for block, op in graph.iterblockops()]
+ check_call(ops[-3], 'virtual_ref')
+ check_call(ops[-2], 'force_virtual_if_necessary')
+ check_call(ops[-1], 'virtual_ref_finish')
+
def test_make_vref_simple(self):
class X:
pass
@@ -25,9 +49,9 @@
#
def f():
x = X()
- exctx.topframeref = virtual_ref(x)
+ exctx.topframeref = vref = virtual_ref(x)
exctx.topframeref = vref_None
- virtual_ref_finish(x)
+ virtual_ref_finish(vref, x)
return 1
#
self.interp_operations(f, [])
@@ -60,8 +84,9 @@
exctx._frame = x
exctx.topframeref = virtual_ref(x)
def leave():
+ vref = exctx.topframeref
exctx.topframeref = vref_None
- virtual_ref_finish(exctx._frame)
+ virtual_ref_finish(vref, exctx._frame)
def f(n):
enter(n)
n = external(n)
@@ -125,7 +150,8 @@
#
@dont_look_inside
def g(vref):
- debug_print(lltype.Void, '-+-+-+-+- external read:', vref().n)
+ # we cannot do anything with the vref after the call to finish()
+ pass
#
def f(n):
while n > 0:
@@ -136,7 +162,7 @@
exctx.topframeref = vref = virtual_ref(x)
# here, 'x' should be virtual
exctx.topframeref = vref_None
- virtual_ref_finish(x)
+ virtual_ref_finish(vref, x)
# 'x' and 'vref' can randomly escape after the call to
# finish().
g(vref)
@@ -144,7 +170,7 @@
return 1
#
self.meta_interp(f, [10])
- self.check_loops(new_with_vtable=2) # the vref and the X
+ self.check_loops(new_with_vtable=1) # the vref
self.check_aborted_count(0)
def test_simple_all_removed(self):
@@ -169,13 +195,13 @@
xy.next1 = lltype.malloc(A, 0)
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
exctx.topframeref = vref_None
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
#
self.meta_interp(f, [15])
self.check_loops(new_with_vtable=0, # all virtualized
@@ -206,17 +232,17 @@
xy.next1 = lltype.malloc(A, 0)
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
exctx.topframeref = vref_None
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
#
self.meta_interp(f, [15])
- self.check_loops(new_with_vtable=2, # the vref, and xy so far,
- new_array=0) # but not xy.next1/2/3
+ self.check_loops(new_with_vtable=1, # the vref: xy doesn't need to be forced
+ new_array=0) # and neither xy.next1/2/3
self.check_aborted_count(0)
def test_simple_force_always(self):
@@ -244,12 +270,12 @@
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
exctx.topframeref = vref_None
#
self.meta_interp(f, [15])
@@ -282,19 +308,19 @@
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
exctx.topframeref = vref_None
return exctx.m
#
res = self.meta_interp(f, [30])
assert res == 13
- self.check_loops(new_with_vtable=2, # the vref, XY() at the end
- new_array=0) # but not next1/2/3
+ self.check_loops(new_with_vtable=1, # the vref, but not XY()
+ new_array=0) # and neither next1/2/3
self.check_loop_count(1)
self.check_aborted_count(0)
@@ -322,7 +348,7 @@
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
if n == 13:
externalfn(n)
n -= 1
@@ -330,7 +356,7 @@
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return exctx.m
#
res = self.meta_interp(f, [30])
@@ -366,7 +392,7 @@
xy.next4 = lltype.malloc(A, 0)
xy.next5 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
if n % 6 == 0:
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
@@ -379,7 +405,7 @@
xy.next3 = lltype.nullptr(A)
xy.next4 = lltype.nullptr(A)
xy.next5 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return exctx.m
#
res = self.meta_interp(f, [72])
@@ -389,36 +415,6 @@
new_array=2) # bridge: next4, next5
self.check_aborted_count(0)
- def test_access_vref_later(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- #
- class XY:
- pass
- class ExCtx:
- pass
- exctx = ExCtx()
- #
- @dont_look_inside
- def g():
- return exctx.later().n
- #
- def f(n):
- while n > 0:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- xy = XY()
- xy.n = n
- exctx.topframeref = virtual_ref(xy)
- exctx.later = exctx.topframeref
- n -= 1
- exctx.topframeref = vref_None
- virtual_ref_finish(xy)
- return g()
- #
- res = self.meta_interp(f, [15])
- assert res == 1
- self.check_aborted_count(0)
-
def test_jit_force_virtual_seen(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
@@ -435,12 +431,12 @@
myjitdriver.jit_merge_point(n=n)
xy = XY()
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
xy.next1 = lltype.malloc(A, 0)
n = exctx.topframeref().n - 1
xy.next1 = lltype.nullptr(A)
exctx.topframeref = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return 1
#
res = self.meta_interp(f, [15])
@@ -465,12 +461,12 @@
if reclevel == 0:
return n
xy = XY()
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
m = f(xy, n, reclevel-1)
assert m == n
n -= 1
exctx.topframeref = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return 2
def main(n, reclevel):
return f(XY(), n, reclevel)
@@ -495,7 +491,7 @@
frame.n += 1
xy = XY()
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
if reclevel > 0:
m = f(xy, frame.n, reclevel-1)
assert xy.n == m
@@ -503,7 +499,7 @@
else:
n -= 2
exctx.topframeref = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return frame.n
def main(n, reclevel):
return f(XY(), n, reclevel)
@@ -512,6 +508,93 @@
assert res == main(10, 2)
self.check_aborted_count(0)
+ def test_alloc_virtualref_and_then_alloc_structure(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n'])
+ #
+ class XY:
+ pass
+ class ExCtx:
+ pass
+ exctx = ExCtx()
+ @dont_look_inside
+ def escapexy(xy):
+ print 'escapexy:', xy.n
+ if xy.n % 5 == 0:
+ vr = exctx.vr
+ print 'accessing via vr:', vr()
+ assert vr() is xy
+ #
+ def f(n):
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n)
+ xy = XY()
+ xy.n = n
+ vr = virtual_ref(xy)
+ # force the virtualref to be allocated
+ exctx.vr = vr
+ # force xy to be allocated
+ escapexy(xy)
+ # clean up
+ exctx.vr = vref_None
+ virtual_ref_finish(vr, xy)
+ n -= 1
+ return 1
+ #
+ res = self.meta_interp(f, [15])
+ assert res == 1
+ self.check_loops(new_with_vtable=2) # vref, xy
+
+ def test_cannot_use_invalid_virtualref(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n'])
+ #
+ class XY:
+ n = 0
+ #
+ def fn(n):
+ res = False
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n)
+ myjitdriver.jit_merge_point(n=n)
+ xy = XY()
+ xy.n = n
+ vref = virtual_ref(xy)
+ virtual_ref_finish(vref, xy)
+ vref() # raises InvalidVirtualRef when jitted
+ n -= 1
+ return res
+ #
+ py.test.raises(InvalidVirtualRef, "fn(10)")
+ py.test.raises(LLException, "self.meta_interp(fn, [10])")
+
+ def test_call_virtualref_already_forced(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n', 'res'])
+ #
+ class XY:
+ n = 0
+ #
+ @dont_look_inside
+ def force_it(vref, n):
+ if n % 6 == 0:
+ return vref().n
+ return 0
+ def fn(n):
+ res = 0
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n, res=res)
+ myjitdriver.jit_merge_point(n=n, res=res)
+ xy = XY()
+ xy.n = n
+ vref = virtual_ref(xy)
+ force_it(vref, n)
+ virtual_ref_finish(vref, xy)
+ res += force_it(vref, n) # doesn't raise, because it was already forced
+ n -= 1
+ return res
+ #
+ assert fn(10) == 6
+ res = self.meta_interp(fn, [10])
+ assert res == 6
+
class TestLLtype(VRefTests, LLJitMixin):
pass
diff --git a/pypy/jit/metainterp/test/test_ztranslation.py b/pypy/jit/metainterp/test/test_ztranslation.py
--- a/pypy/jit/metainterp/test/test_ztranslation.py
+++ b/pypy/jit/metainterp/test/test_ztranslation.py
@@ -2,7 +2,7 @@
from pypy.jit.metainterp.warmspot import rpython_ll_meta_interp, ll_meta_interp
from pypy.jit.backend.llgraph import runner
from pypy.rlib.jit import JitDriver, unroll_parameters
-from pypy.rlib.jit import PARAMETERS, dont_look_inside
+from pypy.rlib.jit import PARAMETERS, dont_look_inside, hint
from pypy.jit.metainterp.jitprof import Profiler
from pypy.rpython.lltypesystem import lltype, llmemory
@@ -24,16 +24,21 @@
# - string concatenation, slicing and comparison
class Frame(object):
- _virtualizable2_ = ['i']
+ _virtualizable2_ = ['l[*]']
def __init__(self, i):
- self.i = i
+ self = hint(self, fresh_virtualizable=True,
+ access_directly=True)
+ self.l = [i]
class OtherFrame(object):
- _virtualizable2_ = ['i']
+ _virtualizable2_ = ['i', 'l[*]']
def __init__(self, i):
+ self = hint(self, fresh_virtualizable=True,
+ access_directly=True)
self.i = i
+ self.l = [float(i)]
class JitCellCache:
entry = None
@@ -57,39 +62,45 @@
jitdriver.set_param("trace_eagerness", 2)
total = 0
frame = Frame(i)
- while frame.i > 3:
+ while frame.l[0] > 3:
jitdriver.can_enter_jit(frame=frame, total=total)
jitdriver.jit_merge_point(frame=frame, total=total)
- total += frame.i
- if frame.i >= 20:
- frame.i -= 2
- frame.i -= 1
+ total += frame.l[0]
+ if frame.l[0] >= 20:
+ frame.l[0] -= 2
+ frame.l[0] -= 1
return total * 10
#
- myjitdriver2 = JitDriver(greens = ['g'], reds = ['m', 's', 'f'],
+ myjitdriver2 = JitDriver(greens = ['g'],
+ reds = ['m', 's', 'f', 'float_s'],
virtualizables = ['f'])
def f2(g, m, x):
s = ""
f = OtherFrame(x)
+ float_s = 0.0
while m > 0:
- myjitdriver2.can_enter_jit(g=g, m=m, f=f, s=s)
- myjitdriver2.jit_merge_point(g=g, m=m, f=f, s=s)
+ myjitdriver2.can_enter_jit(g=g, m=m, f=f, s=s, float_s=float_s)
+ myjitdriver2.jit_merge_point(g=g, m=m, f=f, s=s,
+ float_s=float_s)
s += 'xy'
if s[:2] == 'yz':
return -666
m -= 1
f.i += 3
+ float_s += f.l[0]
return f.i
#
def main(i, j):
return f(i) - f2(i+j, i, j)
res = ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass,
- type_system=self.type_system)
+ type_system=self.type_system,
+ listops=True)
assert res == main(40, 5)
res = rpython_ll_meta_interp(main, [40, 5],
CPUClass=self.CPUClass,
type_system=self.type_system,
- ProfilerClass=Profiler)
+ ProfilerClass=Profiler,
+ listops=True)
assert res == main(40, 5)
def test_external_exception_handling_translates(self):
diff --git a/pypy/jit/metainterp/typesystem.py b/pypy/jit/metainterp/typesystem.py
--- a/pypy/jit/metainterp/typesystem.py
+++ b/pypy/jit/metainterp/typesystem.py
@@ -5,7 +5,7 @@
from pypy.rpython.annlowlevel import cast_instance_to_base_obj
from pypy.jit.metainterp import history
from pypy.jit.codewriter import heaptracker
-from pypy.rlib.objectmodel import r_dict
+from pypy.rlib.objectmodel import r_dict, specialize
def deref(T):
if isinstance(T, lltype.Ptr):
@@ -97,12 +97,15 @@
def cast_to_baseclass(self, value):
return lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), value)
+ @specialize.ll()
def getlength(self, array):
return len(array)
+ @specialize.ll()
def getarrayitem(self, array, i):
return array[i]
+ @specialize.ll()
def setarrayitem(self, array, i, newvalue):
array[i] = newvalue
@@ -201,12 +204,15 @@
def cast_to_baseclass(self, value):
return ootype.cast_from_object(ootype.ROOT, value)
+ @specialize.ll()
def getlength(self, array):
return array.ll_length()
+ @specialize.ll()
def getarrayitem(self, array, i):
return array.ll_getitem_fast(i)
+ @specialize.ll()
def setarrayitem(self, array, i, newvalue):
array.ll_setitem_fast(i, newvalue)
diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py
--- a/pypy/jit/metainterp/virtualref.py
+++ b/pypy/jit/metainterp/virtualref.py
@@ -2,7 +2,7 @@
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass
from pypy.jit.metainterp import history
from pypy.jit.codewriter import heaptracker
-
+from pypy.rlib.jit import InvalidVirtualRef
class VirtualRefInfo:
@@ -38,23 +38,24 @@
def replace_force_virtual_with_call(self, graphs):
# similar to rvirtualizable2.replace_force_virtualizable_with_call().
- c_funcptr = None
- count = 0
+ c_force_virtual_ptr = None
+ force_virtual_count = 0
for graph in graphs:
for block in graph.iterblocks():
for op in block.operations:
if op.opname == 'jit_force_virtual':
# first compute c_funcptr, but only if there is any
# 'jit_force_virtual' around
- if c_funcptr is None:
- c_funcptr = self.get_force_virtual_fnptr()
+ if c_force_virtual_ptr is None:
+ c_force_virtual_ptr = self.get_force_virtual_fnptr()
#
op.opname = 'direct_call'
- op.args = [c_funcptr, op.args[0]]
- count += 1
- if c_funcptr is not None:
- log("replaced %d 'jit_force_virtual' with %r" % (count,
- c_funcptr.value))
+ op.args = [c_force_virtual_ptr, op.args[0]]
+ force_virtual_count += 1
+ #
+ if c_force_virtual_ptr is not None:
+ log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count,
+ c_force_virtual_ptr.value))
# ____________________________________________________________
@@ -145,7 +146,8 @@
ResumeGuardForcedDescr.force_now(self.cpu, token)
assert vref.virtual_token == self.TOKEN_NONE
assert vref.forced
- else:
- assert vref.forced
+ elif not vref.forced:
+ # token == TOKEN_NONE and the vref was not forced: it's invalid
+ raise InvalidVirtualRef
return vref.forced
force_virtual._dont_inline_ = True
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
@@ -566,6 +566,19 @@
return can_inline_greenargs(*greenargs)
self.can_inline_greenargs = can_inline_greenargs
self.can_inline_callable = can_inline_callable
+ if hasattr(jd.jitdriver, 'on_compile'):
+ def on_compile(logger, token, operations, type, greenkey):
+ greenargs = unwrap_greenkey(greenkey)
+ return jd.jitdriver.on_compile(logger, token, operations, type,
+ *greenargs)
+ def on_compile_bridge(logger, orig_token, operations, n):
+ return jd.jitdriver.on_compile_bridge(logger, orig_token,
+ operations, n)
+ jd.on_compile = on_compile
+ jd.on_compile_bridge = on_compile_bridge
+ else:
+ jd.on_compile = lambda *args: None
+ jd.on_compile_bridge = lambda *args: None
def get_assembler_token(greenkey, redboxes):
# 'redboxes' is only used to know the types of red arguments
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -42,6 +42,7 @@
config.objspace.usemodules._lsprof = True
#
config.objspace.usemodules._ffi = True
+config.objspace.usemodules.micronumpy = True
#
set_pypy_opt_level(config, level='jit')
diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py
--- a/pypy/jit/tl/pypyjit_demo.py
+++ b/pypy/jit/tl/pypyjit_demo.py
@@ -1,11 +1,10 @@
try:
- def f(x):
- i = 0
- while i < x:
- range(i)
- i += 1
- f(10000)
+ import numpy
+ a = numpy.array(range(10))
+ b = a + a + a
+ print b[3]
+
except Exception, e:
print "Exception: ", type(e)
print e
diff --git a/pypy/jit/tl/tinyframe/test/test_tinyframe.py b/pypy/jit/tl/tinyframe/test/test_tinyframe.py
--- a/pypy/jit/tl/tinyframe/test/test_tinyframe.py
+++ b/pypy/jit/tl/tinyframe/test/test_tinyframe.py
@@ -96,11 +96,12 @@
RETURN r1
''')
s = StringIO()
+ prev = sys.stdout
sys.stdout = s
try:
interpret(code)
finally:
- sys.stdout = sys.__stdout__
+ sys.stdout = prev
lines = s.getvalue().splitlines()
assert lines == [
'0',
diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py
--- a/pypy/jit/tl/tl.py
+++ b/pypy/jit/tl/tl.py
@@ -40,6 +40,7 @@
assert n >= 0
self.stack[n] = elem
+ @dont_look_inside
def roll(self, r):
if r < -1:
i = self.stackpos + r
diff --git a/pypy/jit/tool/cpython.vmrss b/pypy/jit/tool/cpython.vmrss
deleted file mode 100644
--- a/pypy/jit/tool/cpython.vmrss
+++ /dev/null
@@ -1,4101 +0,0 @@
-124
-16600
-20620
-20640
-22036
-94084
-94084
-94108
-94108
-94108
-94108
-94108
-94120
-94164
-94160
-94160
-94160
-94160
-94160
-94216
-110644
-123144
-135236
-143680
-148500
-153104
-157088
-160640
-164760
-167992
-163108
-163232
-163232
-163436
-163436
-163436
-163444
-163444
-163444
-163448
-163448
-163448
-163448
-163448
-163448
-167060
-170948
-174432
-177212
-177216
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176508
-176520
-176520
-176520
-176520
-176520
-176520
-176520
-176520
-176520
-176540
-176544
-176544
-176544
-176544
-176544
-176544
-176544
-176544
-176544
-176544
-176544
-176544
-179120
-187120
-189380
-191052
-192156
-193320
-194900
-195860
-198516
-201484
-202600
-202600
-202600
-202600
-202832
-202832
-202836
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-202840
-207784
-212136
-216320
-220508
-224696
-228876
-245088
-245088
-247844
-252032
-256212
-260400
-264592
-268776
-272776
-275060
-279244
-283428
-287616
-291032
-293900
-298080
-302272
-304364
-308548
-310644
-312740
-316924
-319016
-323208
-325296
-327392
-331572
-333668
-335760
-337856
-354328
-356424
-358520
-362700
-364792
-366892
-368984
-371080
-373168
-375260
-377356
-379448
-381540
-383636
-383636
-385732
-387820
-390032
-391160
-392292
-394552
-396816
-397092
-399072
-401340
-403600
-405860
-408008
-408148
-412640
-414900
-417164
-419420
-421680
-423944
-426204
-428464
-430724
-432768
-434980
-436476
-437932
-440332
-441984
-442740
-445152
-447688
-449148
-449960
-452436
-454712
-454896
-457180
-458888
-459688
-462040
-463480
-464408
-466812
-467244
-469224
-471096
-471684
-474136
-474328
-476508
-478872
-481356
-483472
-483780
-486072
-488480
-489668
-490888
-493420
-495704
-496836
-498116
-500520
-502756
-503668
-505400
-507760
-509296
-510204
-512764
-514708
-515508
-517372
-519764
-520648
-522188
-524596
-525524
-527004
-529412
-534224
-536632
-538080
-539216
-541588
-542560
-543384
-543384
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-518804
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519024
-519028
-519028
-519028
-519028
-519028
-519028
-519028
-519028
-519028
-519028
-519028
-519028
-519032
-519032
-519032
-519032
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519036
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519048
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519052
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519056
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519060
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519064
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-519068
-520592
-520592
-520904
-522740
-522740
-523212
-525256
-525256
-525316
-526552
-526552
-526560
-528508
-528508
-528508
-530040
-530040
-530040
-532684
-532684
-532684
-534948
-534948
-534948
-538028
-538028
-538028
-541404
-541448
-541448
-543784
-543784
-543784
-545184
-545476
-545768
-545832
-545832
-545832
-546016
-546016
-546128
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546184
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546228
-546708
-546708
-546708
-547988
-550420
-550420
-550420
-552896
-555796
-555796
-555796
-559136
-560280
-560280
-560996
-562504
-563772
-564672
-564672
-565268
-567936
-568884
-569028
-569236
-569292
-569292
-570236
-572960
-573980
-573980
-574508
-577404
-579188
-579188
-579508
-582836
-584468
-584468
-585544
-591292
-591292
-591292
-595868
-597588
-597588
-598404
-602772
-603964
-603964
-605488
-609740
-610468
-610468
-611884
-616440
-617108
-617108
-618156
-622276
-623784
-623784
-624128
-624376
-625544
-626736
-627112
-627112
-627116
-627656
-628836
-628836
-628836
-629160
-630180
-630488
-630488
-630492
-631288
-632144
-632144
-632144
-632172
-632688
-633220
-633220
-633220
-633284
-633756
-633916
-633916
-633916
-634012
-634608
-634608
-634608
-634624
-634732
-635144
-635144
-635144
-635196
-635680
-635868
-635868
-635944
-638440
-639964
-639980
-639980
-640056
-641052
-642064
-642064
-642064
-642248
-643080
-643832
-643832
-643832
-644116
-646500
-647424
-648236
-649032
-649156
-649156
-649256
-651556
-652056
-652504
-652860
-653168
-653440
-653876
-654096
-654304
-654304
-654304
-654756
-655648
-657064
-657064
-657064
-657064
-657488
-657756
-657756
-657756
-658112
-658736
-658736
-658736
-658796
-659304
-659376
-659376
-659376
-659848
-661000
-661172
-661172
-661236
-662240
-663240
-663508
-663508
-663660
-664324
-665512
-665764
-665764
-665764
-666448
-667692
-668112
-668112
-668112
-668624
-669508
-670388
-670536
-670536
-670536
-670564
-671288
-672268
-672268
-672268
-672676
-674504
-675072
-675072
-675072
-675156
-675896
-676700
-676700
-676700
-676820
-677988
-678628
-678628
-678628
-678776
-679744
-680400
-680400
-680400
-705092
-705156
-705156
-705156
-705156
-705156
-705156
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705160
-705264
-705264
-705264
-705400
-705476
-706168
-706292
-706292
-706292
-706504
-706568
-706980
-707012
-707012
-707012
-707196
-707280
-707904
-707904
-707904
-707924
-708112
-708176
-708676
-708676
-708676
-708696
-708892
-708984
-709588
-709588
-709588
-709612
-709804
-709848
-710300
-710300
-710300
-710676
-710520
-710604
-711156
-711156
-711156
-711336
-711352
-711576
-712080
-712080
-712080
-712300
-712408
-712500
-712648
-712648
-712648
-712648
-713060
-713300
-713716
-713716
-713716
-714072
-714196
-714568
-714568
-714568
-714596
-714956
-715112
-715808
-715808
-715808
-717504
-717628
-717660
-717660
-717660
-718620
-719048
-719424
-719424
-719424
-719480
-719924
-720612
-720612
-720612
-720620
-722584
-722848
-722848
-722848
-723060
-724108
-724604
-724604
-724604
-725108
-726168
-726348
-726348
-726348
-727216
-728204
-728204
-728204
-728324
-729396
-730152
-730152
-730152
-730396
-736796
-736800
-736800
-736800
-736800
-736800
-736800
-736800
-736800
-737136
-738296
-738400
-738400
-738400
-739092
-740128
-740128
-740128
-740140
-741092
-741980
-741980
-741980
-742060
-743060
-743796
-743796
-743796
-743836
-744440
-745348
-745348
-745348
-745400
-746108
-746848
-746952
-746952
-746952
-747496
-748608
-748744
-749084
-749084
-749084
-749172
-750172
-751468
-751592
-751592
-751592
-751688
-751928
-752152
-752308
-759152
-760152
-760152
-760152
-756356
-754816
-756356
-756356
-756356
-756688
-756688
-756820
-757152
-757200
-757400
-757432
-757432
-757432
-757632
-757956
-758404
-758844
-759480
-760064
-760552
-760552
-760552
-760560
-761180
-761632
-762288
-762800
-763700
-764504
-764716
-764716
-764716
-764940
-765388
-765936
-767748
-767056
-767300
-767484
-767868
-768316
-768316
-768316
-768316
-768700
-768828
-768700
-769340
-769260
-771008
-771552
-771652
-771716
-772580
-772708
-772740
-772740
-772740
-772292
-772740
-772944
-773188
-773700
-774084
-774084
-774404
-774020
-774532
-774020
-774596
-774340
-774468
-774468
-774468
-774724
-774792
-774980
-775368
-775816
-775816
-776264
-777480
-778292
-778408
-778440
-778440
-778440
-778440
-778440
-778440
-778440
-778440
-778440
-778440
-778440
-778632
-778696
-778952
-779016
-779016
-779016
-779016
-780812
-780812
-780812
-781068
-781580
-781772
-781712
-781868
-782092
-782420
-782796
-782796
-782796
-782796
-782668
-783128
-783436
-783820
-784076
-784332
-784908
-785164
-785500
-786188
-786188
-786188
-786188
-786188
-786188
-786188
-786412
-786896
-787084
-787404
-787532
-787724
-787568
-788108
-788428
-788748
-788752
-789520
-789520
-789520
-788880
-789440
-789452
-789516
-790092
-790284
-790604
-790860
-791052
-791372
-791628
-792012
-792012
-792396
-792780
-792780
-792780
-792780
-792780
-793228
-793228
-793868
-793868
-793996
-793996
-794636
-794636
-794636
-795084
-795084
-795468
-795532
-795980
-795980
-796300
-796364
-796364
-796364
-796364
-796748
-797132
-797132
-797516
-797644
-797644
-798380
-798604
-798860
-798924
-799372
-799564
-799756
-799756
-799756
-799756
-799816
-800292
-800792
-801312
-801816
-802364
-802880
-803456
-803660
-803660
-803660
-803812
-804388
-804960
-805516
-806084
-806668
-807324
-807980
-807980
-807980
-807980
-808416
-809084
-809784
-810492
-811160
-812900
-813476
-813876
-813876
-813876
-813876
-814508
-815152
-815864
-816556
-817260
-817916
-818708
-819272
-819352
-819352
-819352
-819352
-819884
-820308
-820888
-821012
-821012
-821204
-821588
-821588
-821588
-821972
-822228
-822164
-822932
-823252
-823252
-823252
-823252
-823252
-823256
-823612
-823920
-823936
-824140
-824168
-824220
-824280
-824400
-824664
-825776
-825776
-825776
-825776
-832168
-832168
-832168
-832168
-832808
-833492
-833492
-833492
-833492
-833700
-834308
-834428
-834428
-834428
-834780
-836216
-836216
-836216
-836836
-839308
-839308
-839308
-839308
-839416
-840344
-840344
-840344
-840344
-841724
-841724
-841724
-841724
-843800
-843800
-843800
-843800
-845692
-846072
-846072
-846072
-846096
-846736
-847096
-847156
-847156
-847156
-847160
-847180
-847360
-847360
-847360
-847360
-847416
-849248
-849248
-849248
-849248
-849716
-849716
-849716
-849716
-849740
-851168
-851168
-851168
-851168
-854544
-854544
-854544
-854544
-854564
-855332
-855332
-855332
-855332
-857092
-857092
-857092
-857092
-858000
-859388
-859388
-859388
-859388
-861584
-861584
-861584
-861584
-861584
-863464
-863464
-863464
-863464
-864304
-866500
-866500
-866500
-866500
-868952
-868952
-868952
-868952
-869740
-872108
-872108
-872108
-872108
-873208
-875564
-875564
-875564
-875564
-878568
-878568
-878568
-878568
-878576
-880780
-880780
-880780
-880780
-884048
-884048
-884048
-884048
-884048
-884048
-886516
-886516
-886516
-886516
-886516
-886536
-888112
-888112
-888112
-888112
-888112
-888112
-888656
-888984
-888984
-888984
-888984
-888984
-888984
-889076
-890288
-890288
-890288
-890288
-890288
-890288
-890404
-892900
-892900
-892900
-892900
-892900
-892900
-892900
-892900
-895760
-895760
-895760
-895760
-895760
-895760
-895920
-897624
-897624
-897624
-897624
-897624
-897624
-897624
-897624
-897628
-898024
-898024
-898024
-898024
-898024
-898060
-900024
-900024
-900024
-900024
-900024
-900024
-900240
-901436
-901436
-901436
-901436
-901436
-901556
-903116
-903116
-903116
-903116
-903116
-903128
-905084
-905084
-905084
-905084
-905084
-905084
-905096
-906832
-906832
-906832
-906832
-906832
-906832
-908916
-908916
-908916
-908916
-908916
-908916
-908916
-910720
-910720
-910720
-910720
-910720
-910720
-911780
-912072
-912072
-912072
-912072
-914472
-914472
-914472
-914472
-914472
-917120
-917120
-917120
-917120
-917120
-919056
-919056
-919056
-919056
-919056
-920316
-920316
-920316
-920316
-920316
-920892
-920892
-920892
-920892
-920892
-922996
-922996
-922996
-922996
-922996
-925564
-925564
-925564
-925564
-925564
-927780
-927780
-927780
-927780
-928016
-928936
-929048
-930864
-930864
-930864
-930864
-932980
-933304
-933304
-933304
-933304
-933540
-934292
-935452
-935528
-935528
-935528
-935528
-935528
-935528
-935528
-935528
-935600
-936112
-936112
-936208
-936208
-936208
-936208
-936308
-936308
-936316
-936368
-936368
-936368
-936368
-936368
-936368
-936368
-936368
-936368
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-936376
-937404
-937404
-937404
-937404
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-939968
-940516
-940516
-940516
-940516
-947168
-947168
-947168
-947168
-951948
-951948
-951948
-951948
-953488
-956916
-956916
-956916
-956916
-952296
-955376
-953420
-953260
-953900
-953516
-953900
-955052
-953516
-953516
-954284
-953324
-953516
-956208
-956208
-956208
-956208
-954668
-948988
-948988
-948988
-948988
-948988
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-945908
-947704
-948068
-948068
-948068
-948068
-948068
-948552
-949024
-949024
-949024
-949024
-949024
-949944
-950492
-950616
-950616
-950616
-950616
-951416
-952000
-952564
-952564
-952564
-952564
-952620
-953296
-953952
-954332
-954332
-954332
-954332
-954532
-955532
-956216
-956216
-956216
-956216
-956216
-956584
-957396
-957704
-957704
-957704
-957704
-957740
-958620
-959444
-959444
-959444
-959444
-959444
-960224
-963784
-963868
-963868
-963868
-963868
-963872
-964684
-972452
-972452
-972452
-972452
-972452
-972452
-973220
-974548
-974548
-974548
-974548
-974548
-975540
-977704
-978792
-978792
-978792
-978792
-978792
-981296
-982700
-983180
-983180
-983180
-983180
-983368
-985060
-987512
-987688
-987688
-987688
-987688
-988180
-990724
-993084
-993124
-993124
-993124
-993124
-993604
-995444
-996640
-996640
-996640
-996640
-996640
-997892
-999160
-1001452
-1001452
-1001452
-1001452
-1001452
-1002264
-1004120
-1004916
-1004916
-1004916
-1004916
-1004916
-1006648
-1010244
-1010548
-1010548
-1010548
-1010548
-1010572
-1011860
-1013748
-1017264
-1017264
-1017264
-1017264
-1017264
-1019096
-1021044
-1021044
-1021044
-1021044
-1021044
-1021536
-1023636
-1024964
-1024964
-1024964
-1024964
-1024964
-1025592
-1027672
-1029384
-1029384
-1029384
-1029384
-1029384
-1030056
-1032244
-1033756
-1033756
-1033756
-1033756
-1033756
-1034384
-1035856
-1036588
-1038428
-1038428
-1038428
-1038428
-1038428
-1039288
-1041088
-1042508
-1042508
-1042508
-1042508
-1042508
-1043544
-1045280
-1046580
-1046580
-1046580
-1046580
-1046580
-1047040
-1048560
-1049872
-1050576
-1050576
-1050576
-1050576
-1050576
-1052016
-1056044
-1057360
-1057360
-1057360
-1057360
-1057360
-1058336
-1059900
-1061244
-1061704
-1061704
-1061704
-1061704
-1061704
-1063148
-1063972
-1065404
-1067064
-1067536
-1067536
-1067536
-1067536
-1067536
-1069284
-1070524
-1072340
-1072836
-1072836
-1072836
-1072836
-1072836
-1073584
-1074592
-1076404
-1076832
-1076832
-1076832
-1076832
-1076832
-1078124
-1079640
-1080220
-1080644
-1080736
-1080736
-1080736
-1080736
-1080924
-1082868
-1083368
-1084412
-1084412
-1084412
-1084412
-1084412
-1085216
-1087068
-1087960
-1087960
-1087960
-1087960
-1087960
-1089788
-1093132
-1095064
-1095064
-1095064
-1095064
-1095064
-1095140
-1097092
-1098948
-1098948
-1098948
-1098948
-1098948
-1098980
-1100812
-1102032
-1102032
-1102032
-1102032
-1102032
-1105464
-1116944
-1119248
-1120364
-1120364
-1120364
-1120364
-1120364
-1121568
-1122908
-1123680
-1124604
-1125076
-1125076
-1125076
-1125076
-1125076
-1126292
-1128160
-1129952
-1129952
-1129952
-1129952
-1129952
-1130496
-1131884
-1133032
-1134204
-1135460
-1135636
-1135636
-1135636
-1135636
-1135636
-1136764
-1138048
-1139412
-1140764
-1141164
-1141188
-1142440
-1142440
-1142440
-1142440
-1142440
-1142440
-1143980
-1145876
-1146576
-1146576
-1146576
-1146576
-1146576
-1146576
-1147680
-1148328
-1148960
-1148960
-1148960
-1148960
-1148960
-1149004
-1150700
-1152228
-1153364
-1153364
-1153520
-1153784
-1154588
-1154680
-1154712
-1154728
-1154784
-1154992
-1155356
-1155620
-1155856
-1156044
-1156420
-1157392
-1158760
-1158980
-1158988
-1159000
-1162724
-1162740
-1162788
-1163112
-1163188
-1163188
-1163188
-1163188
-1163188
-1163384
-1165668
-1166648
-1166652
-1166664
-1166676
-1166688
-1166692
-1166696
-1166700
-1166700
-1172848
-1172852
-1174888
-1176824
-1176836
-1176852
-1176860
-1176876
-1176880
-1176888
-1176892
-1176900
-1176912
-1176944
-1177248
-1177712
-1178172
-1178536
-1178656
-1178780
-1178920
-1179044
-1179188
-1179384
-1180296
-1180300
-1180300
-1180300
-1180300
-1180300
-1180300
-1180372
-1180380
-1180468
-1180524
-1180524
-1180524
-1180524
-1180524
-1180576
-1180580
-1180644
-1180684
-1180684
-1180684
-1180684
-1180684
-1180684
-1180724
-1180756
-1180852
-1180904
-1180904
-1180904
-1180904
-1180904
-1180904
-1181096
-1181400
-1181744
-1181744
-1181744
-1181744
-1181744
-1181744
-1181936
-1181936
-1181936
-1181936
-1181936
-1181936
-1181936
-1181936
-1181936
-1181972
-1182004
-1182004
-1182004
-1182004
-1182004
-1182004
-1182004
-1182004
-1182004
-1182128
-1182156
-1182156
-1182156
-1182156
-1182156
-1182156
-1182156
-1182156
-1182180
-1182180
-1182180
-1182180
-1182180
-1182180
-1182180
-1182368
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1182516
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183576
-1183596
-1183772
-1183772
-1183772
-1183772
-1183772
-1183772
-1183772
-1183772
-1183772
-1183776
-1183776
-1183776
-1183776
-1183776
-1183776
-1183776
-1183776
-1183776
-1183952
-1184000
-1184000
-1184000
-1184000
-1184000
-1184000
-1184000
-1184200
-1184832
-1184832
-1184832
-1184832
-1184832
-1184832
-1184928
-1184928
-1184940
-1184940
-1184940
-1184940
-1184940
-1184940
-1184940
-1184940
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185144
-1185196
-1185196
-1185196
-1185196
-1185196
-1185196
-1185196
-1185196
-1185196
-1185268
-1185268
-1185268
-1185268
-1185268
-1185268
-1185268
-1185268
-1186444
-1186776
-1186776
-1186776
-1186776
-1186776
-1187664
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188072
-1188168
-1188168
-1188168
-1188168
-1188168
-1188168
-1188168
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189240
-1189292
-1189292
-1189292
-1189292
-1189292
-1189292
-1189292
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189532
-1189704
-1189708
-1189708
-1189708
-1189708
-1189708
-1190160
-1190160
-1190160
-1190160
-1190160
-1190160
-1190160
-1190160
-1190160
-1191100
-1191100
-1191100
-1191100
-1191100
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191316
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191748
-1191772
-1191772
-1191772
-1191772
-1191772
-1191772
-1191772
-1191772
-1192964
-1192964
-1192964
-1192964
-1192964
-1192964
-1192964
-1193060
-1193060
-1193060
-1193060
-1193060
-1193060
-1193060
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193072
-1193076
-1193076
-1193076
-1193076
-1193076
-1193076
-1193124
-1193124
-1193360
-1194108
-1194108
-1194108
-1194108
-1194108
-1193380
-1193460
-1193460
-1193460
-1193460
-1193460
-1193460
-1193460
-1193460
-1193792
-1193792
-1193792
-1193792
-1193792
-1193792
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194000
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194048
-1194328
-1194328
-1194328
-1194328
-1194328
-1194328
-1194328
-1194328
-1194328
-1194328
-1194360
-1194360
-1194360
-1194360
-1194360
-1194360
-1194360
-1194508
-1194508
-1194508
-1194508
-1194508
-1194508
-1194512
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194668
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1194912
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196596
-1196660
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196764
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1196948
-1197236
-1197236
-1197236
-1197236
-1197236
-1197236
-1197236
-1197236
-1197236
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197288
-1197376
-1197384
-1197596
-1197596
-1197596
-1197596
-1197596
-1197596
-1197596
-1197596
-1197588
-1197588
-1197588
-1197588
-1197588
-1197588
-1197588
-1197588
-1197564
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197460
-1197492
-1197508
-1197516
-1197516
-1197516
-1197516
-1197516
-1197516
diff --git a/pypy/module/__builtin__/app_inspect.py b/pypy/module/__builtin__/app_inspect.py
--- a/pypy/module/__builtin__/app_inspect.py
+++ b/pypy/module/__builtin__/app_inspect.py
@@ -5,6 +5,8 @@
import sys
+from __pypy__ import lookup_special
+
def _caller_locals():
# note: the reason why this is working is because the functions in here are
# compiled by geninterp, so they don't have a frame
@@ -62,7 +64,22 @@
obj = args[0]
- if isinstance(obj, types.ModuleType):
+ dir_meth = None
+ if isinstance(obj, types.InstanceType):
+ try:
+ dir_meth = getattr(obj, "__dir__")
+ except AttributeError:
+ pass
+ else:
+ dir_meth = lookup_special(obj, "__dir__")
+ if dir_meth is not None:
+ result = dir_meth()
+ if not isinstance(result, list):
+ raise TypeError("__dir__() must return a list, not %r" % (
+ type(result),))
+ result.sort()
+ return result
+ elif isinstance(obj, types.ModuleType):
try:
result = list(obj.__dict__)
result.sort()
@@ -76,14 +93,6 @@
result.sort()
return result
- elif hasattr(type(obj), '__dir__'):
- result = type(obj).__dir__(obj)
- if not isinstance(result, list):
- raise TypeError("__dir__() must return a list, not %r" % (
- type(result),))
- result.sort()
- return result
-
else: #(regular item)
Dict = {}
try:
diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -120,15 +120,32 @@
def test_dir_custom(self):
class Foo(object):
def __dir__(self):
- return [1, 3, 2]
+ return ["1", "2", "3"]
f = Foo()
- assert dir(f) == [1, 2, 3]
- #
+ assert dir(f) == ["1", "2", "3"]
+ class Foo:
+ def __dir__(self):
+ return ["apple"]
+ assert dir(Foo()) == ["apple"]
class Foo(object):
def __dir__(self):
return 42
f = Foo()
raises(TypeError, dir, f)
+ import types
+ class Foo(types.ModuleType):
+ def __dir__(self):
+ return ["blah"]
+ assert dir(Foo("a_mod")) == ["blah"]
+
+ def test_dir_custom_lookup(self):
+ class M(type):
+ def __dir__(self, *args): return ["14"]
+ class X(object):
+ __metaclass__ = M
+ x = X()
+ x.__dir__ = lambda x: ["14"]
+ assert dir(x) != ["14"]
def test_format(self):
assert format(4) == "4"
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
@@ -16,6 +16,7 @@
'debug_stop' : 'interp_debug.debug_stop',
'debug_print_once' : 'interp_debug.debug_print_once',
'builtinify' : 'interp_magic.builtinify',
+ 'lookup_special' : 'interp_magic.lookup_special',
}
def setup_after_space_initialization(self):
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
@@ -1,9 +1,9 @@
+from pypy.interpreter.baseobjspace import ObjSpace, W_Root
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec
from pypy.rlib.objectmodel import we_are_translated
from pypy.objspace.std.typeobject import MethodCache
from pypy.objspace.std.mapdict import IndexCache
-from pypy.module._file.interp_file import W_File
def internal_repr(space, w_object):
@@ -59,3 +59,14 @@
func = space.interp_w(Function, w_func)
bltn = BuiltinFunction(func)
return space.wrap(bltn)
+
+ at unwrap_spec(ObjSpace, W_Root, str)
+def lookup_special(space, w_obj, meth):
+ """Lookup up a special method on an object."""
+ if space.is_oldstyle_instance(w_obj):
+ w_msg = space.wrap("this doesn't do what you want on old-style classes")
+ raise OperationError(space.w_TypeError, w_msg)
+ w_descr = space.lookup(w_obj, meth)
+ if w_descr is None:
+ return space.w_None
+ return space.get(w_descr, w_obj)
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
@@ -36,3 +36,16 @@
assert not hasattr(A.b, 'im_func')
assert A.a is not A.__dict__['a']
assert A.b is A.__dict__['b']
+
+ def test_lookup_special(self):
+ from __pypy__ import lookup_special
+ class X(object):
+ def foo(self): return 42
+ x = X()
+ x.foo = 23
+ x.bar = 80
+ assert lookup_special(x, "foo")() == 42
+ assert lookup_special(x, "bar") is None
+ class X:
+ pass
+ raises(TypeError, lookup_special, X(), "foo")
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
@@ -128,6 +128,9 @@
assert ns["x"] == ns["lemon"] == 3
assert ns["apple"] == 4
+ def test_empty_module(self):
+ compile(self.ast.Module([]), "<test>", "exec")
+
def test_ast_types(self):
ast = self.ast
expr = ast.Expr()
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
@@ -4,13 +4,13 @@
import errno
from pypy.rlib import streamio
from pypy.rlib.rarithmetic import r_longlong
-from pypy.module._file.interp_stream import W_AbstractStream
-from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror, wrap_oserror_as_ioerror
+from pypy.rlib.rstring import StringBuilder
+from pypy.module._file.interp_stream import (W_AbstractStream, StreamErrors,
+ wrap_streamerror, wrap_oserror_as_ioerror)
from pypy.module.posix.interp_posix import dispatch_filename
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.interpreter.typedef import interp_attrproperty, make_weakref_descr
-from pypy.interpreter.typedef import interp_attrproperty_w
+from pypy.interpreter.typedef import (TypeDef, GetSetProperty,
+ interp_attrproperty, make_weakref_descr, interp_attrproperty_w)
from pypy.interpreter.gateway import interp2app, unwrap_spec
@@ -43,7 +43,11 @@
# 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()
- self.direct_close()
+ try:
+ self.direct_close()
+ except StreamErrors, e:
+ operr = wrap_streamerror(self.space, e, self.w_name)
+ operr.write_unraisable(self.space, '__del__ of ', self)
def fdopenstream(self, stream, fd, mode, w_name=None):
self.fd = fd
@@ -160,14 +164,14 @@
if n < 0:
return stream.readall()
else:
- result = []
+ result = StringBuilder(n)
while n > 0:
data = stream.read(n)
if not data:
break
n -= len(data)
result.append(data)
- return ''.join(result)
+ return result.build()
@unwrap_spec(size=int)
def direct_readline(self, size=-1):
@@ -345,11 +349,11 @@
may be returned, even if no size parameter was given.""")
_decl(locals(), "readline",
- """readlines([size]) -> list of strings, each a line from the file.
+ """readline([size]) -> next line from the file, as a string.
-Call readline() repeatedly and return a list of the lines so read.
-The optional size argument, if given, is an approximate bound on the
-total number of bytes in the lines returned.""")
+Retain newline. A non-negative size argument limits the maximum
+number of bytes to return (an incomplete line may be returned then).
+Return an empty string at EOF.""")
_decl(locals(), "readlines",
"""readlines([size]) -> list of strings, each a line from the file.
@@ -553,4 +557,4 @@
@unwrap_spec(file=W_File, encoding="str_or_None", errors="str_or_None")
def set_file_encoding(space, file, encoding=None, errors=None):
file.encoding = encoding
- file.errors = errors
\ No newline at end of file
+ file.errors = errors
diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py
--- a/pypy/module/_file/test/test_file.py
+++ b/pypy/module/_file/test/test_file.py
@@ -232,6 +232,29 @@
data = f.read()
assert data == "15"
+ def test_exception_from_close(self):
+ import os
+ f = self.file(self.temppath, 'w')
+ os.close(f.fileno())
+ raises(IOError, f.close) # bad file descriptor
+
+ def test_exception_from_del(self):
+ import os, gc, sys, cStringIO
+ f = self.file(self.temppath, 'w')
+ g = cStringIO.StringIO()
+ preverr = sys.stderr
+ try:
+ sys.stderr = g
+ os.close(f.fileno())
+ del f
+ gc.collect() # bad file descriptor in f.__del__()
+ finally:
+ sys.stderr = preverr
+ import errno
+ assert os.strerror(errno.EBADF) in g.getvalue()
+ # the following is a "nice to have" feature that CPython doesn't have
+ if '__pypy__' in sys.builtin_module_names:
+ assert self.temppath in g.getvalue()
class AppTestConcurrency(object):
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
+from pypy.interpreter.gateway import ObjSpace, interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.error import OperationError
from pypy.module._multibytecodec import c_codecs
@@ -11,6 +11,7 @@
self.name = name
self.codec = codec
+ @unwrap_spec(input=str, errors="str_or_None")
def decode(self, space, input, errors=None):
if errors is not None and errors != 'strict':
raise OperationError(space.w_NotImplementedError, # XXX
@@ -33,8 +34,8 @@
space.wrap("internal codec error"))
return space.newtuple([space.wrap(output),
space.wrap(len(input))])
- decode.unwrap_spec = ['self', ObjSpace, str, 'str_or_None']
+ @unwrap_spec(input=unicode, errors="str_or_None")
def encode(self, space, input, errors=None):
if errors is not None and errors != 'strict':
raise OperationError(space.w_NotImplementedError, # XXX
@@ -57,7 +58,6 @@
space.wrap("internal codec error"))
return space.newtuple([space.wrap(output),
space.wrap(len(input))])
- encode.unwrap_spec = ['self', ObjSpace, unicode, 'str_or_None']
MultibyteCodec.typedef = TypeDef(
@@ -69,6 +69,7 @@
MultibyteCodec.typedef.acceptable_as_base_class = False
+ at unwrap_spec(name=str)
def getcodec(space, name):
try:
codec = c_codecs.getcodec(name)
@@ -76,4 +77,3 @@
raise OperationError(space.w_LookupError,
space.wrap("no such codec is supported."))
return space.wrap(MultibyteCodec(name, codec))
-getcodec.unwrap_spec = [ObjSpace, str]
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
@@ -43,7 +43,7 @@
unwrap_value(space, push_elem, ll_res, 0,
callback_ptr.result, w_res)
except OperationError, e:
- tbprint(space, space.wrap(e.application_traceback),
+ tbprint(space, space.wrap(e.get_traceback()),
space.wrap(e.errorstr(space)))
# force the result to be zero
if callback_ptr.result is not None:
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
@@ -28,7 +28,7 @@
from pypy.module.exceptions.interp_exceptions import W_SystemExit, _new_exception
-from pypy.rlib import rstack # for resume points
+from pypy.rlib import rstack, jit # for resume points
from pypy.tool import stdlib_opcode as pythonopcode
class _AppThunk(AbstractThunk):
@@ -47,9 +47,19 @@
def call(self):
costate = self.costate
w_result = self.space.call_args(self.w_func, self.args)
- rstack.resume_point("appthunk", costate, returns=w_result)
costate.w_tempval = w_result
+class _ResumeThunk(AbstractThunk):
+ def __init__(self, space, costate, w_frame):
+ self.space = space
+ self.costate = costate
+ self.w_frame = w_frame
+
+ def call(self):
+ w_result = resume_frame(self.space, self.w_frame)
+ # costate.w_tempval = w_result #XXX?
+
+
W_CoroutineExit = _new_exception('CoroutineExit', W_SystemExit,
"""Coroutine killed manually.""")
@@ -97,7 +107,6 @@
"cannot switch to an unbound Coroutine"))
state = self.costate
self.switch()
- rstack.resume_point("w_switch", state, space)
w_ret, state.w_tempval = state.w_tempval, space.w_None
return w_ret
@@ -116,7 +125,7 @@
if isinstance(operror, OperationError):
w_exctype = operror.w_type
w_excvalue = operror.get_w_value(space)
- w_exctraceback = operror.application_traceback
+ w_exctraceback = operror.get_traceback()
w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback])
if w_exctype is self.costate.w_CoroutineExit:
@@ -151,7 +160,7 @@
space.gettypeobject(pytraceback.PyTraceback.typedef))):
raise OperationError(space.w_TypeError,
space.wrap("throw: arg 3 must be a traceback or None"))
- operror.application_traceback = tb
+ operror.set_traceback(tb)
self._kill(operror)
@@ -217,75 +226,17 @@
self.parent = space.interp_w(AppCoroutine, w_parent)
ec = self.space.getexecutioncontext()
self.subctx.setstate(space, w_state)
- self.reconstruct_framechain()
if space.is_w(w_thunk, space.w_None):
- self.thunk = None
+ if space.is_w(w_state, space.w_None):
+ self.thunk = None
+ else:
+ self.bind(_ResumeThunk(space, self.costate, self.subctx.topframe))
else:
w_func, w_args, w_kwds = space.unpackiterable(w_thunk,
expected_length=3)
args = Arguments.frompacked(space, w_args, w_kwds)
self.bind(_AppThunk(space, self.costate, w_func, args))
- def reconstruct_framechain(self):
- from pypy.interpreter.pyframe import PyFrame
- from pypy.rlib.rstack import resume_state_create
- if self.subctx.topframe is None:
- self.frame = None
- return
-
- space = self.space
- ec = space.getexecutioncontext()
- costate = self.costate
- # now the big fun of recreating tiny things...
- bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
- # ("coroutine__bind", state)
- _bind_frame = resume_state_create(bottom, "coroutine__bind", costate)
- # ("appthunk", costate, returns=w_result)
- appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate)
- chain = appthunk_frame
- for frame in self.subctx.getframestack():
- assert isinstance(frame, PyFrame)
- # ("execute_frame", self, executioncontext, returns=w_exitvalue)
- chain = resume_state_create(chain, "execute_frame", frame, ec)
- code = frame.pycode.co_code
- # ("dispatch", self, co_code, ec, returns=next_instr)
- chain = resume_state_create(chain, "dispatch", frame, code, ec)
- # ("handle_bytecode", self, co_code, ec, returns=next_instr)
- chain = resume_state_create(chain, "handle_bytecode", frame, code,
- ec)
- instr = frame.last_instr
- opcode = ord(code[instr])
- map = pythonopcode.opmap
- 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
- # ("dispatch_call", self, co_code, next_instr, ec)
- chain = resume_state_create(chain, "dispatch_call", frame, code,
- instr+3, ec)
- instr += 1
- oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
- nargs = oparg & 0xff
- nkwds = (oparg >> 8) & 0xff
- if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
- if nkwds == 0: # only positional arguments
- chain = resume_state_create(chain, 'CALL_METHOD', frame,
- nargs)
- else: # includes keyword arguments
- chain = resume_state_create(chain, 'CALL_METHOD_KW', frame)
- elif opcode == map['CALL_FUNCTION'] and nkwds == 0:
- # Only positional arguments
- # case1: ("CALL_FUNCTION", f, nargs, returns=w_result)
- chain = resume_state_create(chain, 'CALL_FUNCTION', frame,
- nargs)
- else:
- # case2: ("call_function", f, returns=w_result)
- chain = resume_state_create(chain, 'call_function', frame)
-
- # ("w_switch", state, space)
- w_switch_frame = resume_state_create(chain, 'w_switch', costate, space)
- # ("coroutine_switch", state, returns=incoming_frame)
- switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate)
- self.frame = switch_frame
# _mixin_ did not work
for methname in StacklessFlags.__dict__:
@@ -411,3 +362,45 @@
@unwrap_spec(limit=int)
def set_stack_depth_limit(space, limit):
rstack.set_stack_depth_limit(limit)
+
+
+# ___________________________________________________________________
+# unpickling trampoline
+
+def resume_frame(space, w_frame):
+ from pypy.interpreter.pyframe import PyFrame
+ frame = space.interp_w(PyFrame, w_frame, can_be_None=True)
+ w_result = space.w_None
+ operr = None
+ executioncontext = frame.space.getexecutioncontext()
+ while frame is not None:
+ code = frame.pycode.co_code
+ instr = frame.last_instr
+ opcode = ord(code[instr])
+ map = pythonopcode.opmap
+ 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
+ oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
+ nargs = oparg & 0xff
+ nkwds = (oparg >> 8) & 0xff
+ if nkwds == 0: # only positional arguments
+ # fast paths leaves things on the stack, pop them
+ if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
+ frame.dropvalues(nargs + 2)
+ elif opcode == map['CALL_FUNCTION']:
+ frame.dropvalues(nargs + 1)
+
+ # small hack: unlink frame out of the execution context, because
+ # execute_frame will add it there again
+ executioncontext.topframeref = jit.non_virtual_ref(frame.f_backref())
+ frame.last_instr = instr + 1 # continue after the call
+ try:
+ w_result = frame.execute_frame(w_result, operr)
+ except OperationError, operr:
+ pass
+ frame = frame.f_backref()
+ if operr:
+ raise operr
+ return w_result
diff --git a/pypy/module/_stackless/interp_greenlet.py b/pypy/module/_stackless/interp_greenlet.py
--- a/pypy/module/_stackless/interp_greenlet.py
+++ b/pypy/module/_stackless/interp_greenlet.py
@@ -124,7 +124,7 @@
space.gettypeobject(pytraceback.PyTraceback.typedef))):
raise OperationError(space.w_TypeError,
space.wrap("throw: arg 3 must be a traceback or None"))
- operror.application_traceback = tb
+ operror.set_traceback(tb)
# Dead greenlet: turn GreenletExit into a regular return
if self.isdead() and operror.match(space, self.costate.w_GreenletExit):
args_w = [operror.get_w_value(space)]
diff --git a/pypy/module/_stackless/test/test_coroutine.py b/pypy/module/_stackless/test/test_coroutine.py
--- a/pypy/module/_stackless/test/test_coroutine.py
+++ b/pypy/module/_stackless/test/test_coroutine.py
@@ -8,33 +8,6 @@
space = gettestobjspace(usemodules=('_stackless',))
cls.space = space
- def test_pickle_coroutine_empty(self):
- # this test is limited to basic pickling.
- # real stacks can only tested with a stackless pypy build.
- import _stackless as stackless
- co = stackless.coroutine()
- import pickle
- pckl = pickle.dumps(co)
- co2 = pickle.loads(pckl)
- # the empty unpickled coroutine can still be used:
- result = []
- co2.bind(result.append, 42)
- co2.switch()
- assert result == [42]
-
- def test_pickle_coroutine_bound(self):
- import pickle
- import _stackless
- lst = [4]
- co = _stackless.coroutine()
- co.bind(lst.append, 2)
- pckl = pickle.dumps((co, lst))
-
- (co2, lst2) = pickle.loads(pckl)
- assert lst2 == [4]
- co2.switch()
- assert lst2 == [4, 2]
-
def test_raise_propagate(self):
import _stackless as stackless
co = stackless.coroutine()
diff --git a/pypy/module/_stackless/test/test_pickle.py b/pypy/module/_stackless/test/test_pickle.py
--- a/pypy/module/_stackless/test/test_pickle.py
+++ b/pypy/module/_stackless/test/test_pickle.py
@@ -19,9 +19,35 @@
class AppTestPickle:
def setup_class(cls):
- if not option.runappdirect:
- py.test.skip('pure appdirect test (run with -A)')
- cls.space = gettestobjspace(usemodules=('_stackless',))
+ cls.space = gettestobjspace(usemodules=('_stackless',), CALL_METHOD=True)
+
+ def test_pickle_coroutine_empty(self):
+ # this test is limited to basic pickling.
+ # real stacks can only tested with a stackless pypy build.
+ import _stackless as stackless
+ co = stackless.coroutine()
+ import pickle
+ pckl = pickle.dumps(co)
+ co2 = pickle.loads(pckl)
+ # the empty unpickled coroutine can still be used:
+ result = []
+ co2.bind(result.append, 42)
+ co2.switch()
+ assert result == [42]
+
+ def test_pickle_coroutine_bound(self):
+ import pickle
+ import _stackless
+ lst = [4]
+ co = _stackless.coroutine()
+ co.bind(lst.append, 2)
+ pckl = pickle.dumps((co, lst))
+
+ (co2, lst2) = pickle.loads(pckl)
+ assert lst2 == [4]
+ co2.switch()
+ assert lst2 == [4, 2]
+
def test_simple_ish(self):
@@ -58,6 +84,113 @@
finally:
del sys.modules['mod']
+ def test_pickle_again(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x):
+ if n == 0:
+ coro.switch()
+ return
+ f(coro, n-1, 2*x)
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+ pckl = pickle.dumps(new_coro)
+ newer_coro = pickle.loads(pckl)
+
+ newer_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
+ def test_kwargs(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x, step=4):
+ if n == 0:
+ coro.switch()
+ return
+ f(coro, n-1, 2*x, step=1)
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+
+ new_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
+ def test_starstarargs(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x, step=4):
+ if n == 0:
+ coro.switch()
+ return
+ f(coro, n-1, 2*x, **{'step': 1})
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+
+ new_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
def test_closure(self):
import new, sys
@@ -130,8 +263,55 @@
finally:
del sys.modules['mod']
+ def test_exception_after_unpickling(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x):
+ if n == 0:
+ coro.switch()
+ raise ValueError
+ try:
+ f(coro, n-1, 2*x)
+ finally:
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+
+ try:
+ sub_coro.switch()
+ except ValueError:
+ pass
+ else:
+ assert 0
+ try:
+ new_coro.switch()
+ except ValueError:
+ pass
+ else:
+ assert 0
+
+example()
+assert output == [16, 8, 4, 2, 1] * 2
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
def test_loop(self):
- #skip("happily segfaulting")
import new, sys
mod = new.module('mod')
diff --git a/pypy/module/_stackless/test/test_pickle_infrastructure.py b/pypy/module/_stackless/test/test_pickle_infrastructure.py
deleted file mode 100644
--- a/pypy/module/_stackless/test/test_pickle_infrastructure.py
+++ /dev/null
@@ -1,301 +0,0 @@
-from pypy.conftest import gettestobjspace
-from py.test import skip
-
-
-class BaseAppTestPicklePrerequisites(object):
- OPTIONS = {}
- def setup_class(cls):
- space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS)
- cls.space = space
-
- def test_pickle_switch_function(object):
- import _stackless, pickle
-
- sw = _stackless.coroutine.switch.im_func
- dump = pickle.dumps(sw)
- res = pickle.loads(dump)
-
- assert res is sw
- assert res.func_code is sw.func_code
- assert res.func_doc is sw.func_doc
- assert res.func_globals is sw.func_globals
-
- def test_pickle_switch_function_code(object):
- import _stackless, pickle
-
- sw = _stackless.coroutine.switch.im_func.func_code
- dump = pickle.dumps(sw)
- res = pickle.loads(dump)
-
- assert res is sw
-
-class AppTestPicklePrerequisites(BaseAppTestPicklePrerequisites):
- pass
-
-class AppTestPicklePrerequisitesBuiltinShortcut(BaseAppTestPicklePrerequisites):
- OPTIONS = {"objspace.std.builtinshortcut": True}
-
-class FrameCheck(object):
-
- def __init__(self, name):
- self.name = name
-
- def __eq__(self, frame):
- return frame.pycode.co_name == self.name
-
-class BytecodeCheck(object):
-
- def __init__(self, code, op, arg):
- self.code = code
- self.op = chr(op)+chr(arg & 0xff) + chr(arg >> 8 & 0xff)
-
- def __eq__(self, pos):
- return self.code[pos-3:pos] == self.op
-
-class BaseTestReconstructFrameChain(object):
- OPTIONS = {}
-
- def setup_class(cls):
- space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS)
- cls.space = space
-
- from pypy.rlib import rstack
- cls.old_resume_state_create = rstack.resume_state_create
-
- def tr(prevstate, label, *args):
- if prevstate is None:
- prevstate = []
- return prevstate+[(label, args)]
- rstack.resume_state_create = tr
-
- w_opmap = space.appexec([], """():
- import opcode
-
- return opcode.opmap
- """)
-
- opmap = space.unwrap(w_opmap)
- cls.CALL_FUNCTION = opmap['CALL_FUNCTION']
- cls.CALL_FUNCTION_VAR = opmap['CALL_FUNCTION_VAR']
- cls.CALL_METHOD = opmap['CALL_METHOD']
-
- cls.callmethod = getattr(cls, cls.callmethod_label)
-
- def teardown_class(cls):
- from pypy.rlib import rstack
- rstack.resume_state_create = cls.old_resume_state_create
-
- def start(self, w_coro):
- self.i = 0
- self.frame_to_check = w_coro.frame
- w_coro.frame = None # avoid exploding in kill > __del__
-
- def end(self):
- assert self.i == len(self.frame_to_check)
-
- def check_entry(self, label, *args):
- frame = self.frame_to_check
- assert frame[self.i] == (label, args)
- self.i += 1
-
-
- def test_two_frames_simple(self):
- space = self.space
-
- w_res = space.appexec([], """():
- import _stackless as stackless
- import pickle
-
- main = stackless.coroutine.getcurrent()
- d = {'main': main}
-
- exec \"\"\"
-def f():
- g(1)
-
-def g(x):
- main.switch()
-\"\"\" in d
- f = d['f']
- g = d['g']
-
- co = stackless.coroutine()
- co.bind(f)
- co.switch()
-
- s = pickle.dumps(co)
- co = pickle.loads(s)
-
- return co, f, g
- """)
-
- w_co, w_f, w_g = space.fixedview(w_res)
-
- ec = space.getexecutioncontext()
- fcode = w_f.code.co_code
- gcode = w_g.code.co_code
-
- self.start(w_co)
- e = self.check_entry
- e('yield_current_frame_to_caller_1')
- e('coroutine__bind', w_co.costate)
- e('appthunk', w_co.costate)
- # f
- e('execute_frame', FrameCheck('f'), ec)
- e('dispatch', FrameCheck('f'), fcode, ec)
- e('handle_bytecode', FrameCheck('f'), fcode, ec)
- e('dispatch_call', FrameCheck('f'), fcode,
- BytecodeCheck(fcode, self.CALL_FUNCTION, 1), ec)
- e('CALL_FUNCTION', FrameCheck('f'), 1)
- # g
- e('execute_frame', FrameCheck('g'), ec)
- e('dispatch', FrameCheck('g'), gcode, ec)
- e('handle_bytecode', FrameCheck('g'), gcode, ec)
- e('dispatch_call', FrameCheck('g'), gcode,
- BytecodeCheck(gcode, self.callmethod, 0), ec)
- e(self.callmethod_label, FrameCheck('g'), 0)
- e('w_switch', w_co.costate, space)
- e('coroutine_switch', w_co.costate)
- self.end()
-
- def test_two_frames_stararg(self):
- space = self.space
-
- w_res = space.appexec([], """():
- import _stackless as stackless
- import pickle
-
- main = stackless.coroutine.getcurrent()
- d = {'main': main}
-
- exec \"\"\"
-def f():
- g(4, 3, d=2, *(1,))
-
-def g(a, b, c, d):
- main.switch()
-\"\"\" in d
- f = d['f']
- g = d['g']
-
- co = stackless.coroutine()
- co.bind(f)
- co.switch()
-
- s = pickle.dumps(co)
- co = pickle.loads(s)
-
- return co, f, g
- """)
-
- w_co, w_f, w_g = space.fixedview(w_res)
-
- ec = space.getexecutioncontext()
- fcode = w_f.code.co_code
- gcode = w_g.code.co_code
-
- self.start(w_co)
- e = self.check_entry
- e('yield_current_frame_to_caller_1')
- e('coroutine__bind', w_co.costate)
- e('appthunk', w_co.costate)
- # f
- e('execute_frame', FrameCheck('f'), ec)
- e('dispatch', FrameCheck('f'), fcode, ec)
- e('handle_bytecode', FrameCheck('f'), fcode, ec)
- e('dispatch_call', FrameCheck('f'), fcode,
- BytecodeCheck(fcode, self.CALL_FUNCTION_VAR, 2+(1<<8)), ec)
- e('call_function', FrameCheck('f'))
- # g
- e('execute_frame', FrameCheck('g'), ec)
- e('dispatch', FrameCheck('g'), gcode, ec)
- e('handle_bytecode', FrameCheck('g'), gcode, ec)
- e('dispatch_call', FrameCheck('g'), gcode,
- BytecodeCheck(gcode, self.callmethod, 0), ec)
- e(self.callmethod_label, FrameCheck('g'), 0)
- e('w_switch', w_co.costate, space)
- e('coroutine_switch', w_co.costate)
- self.end()
-
- def test_two_frames_method(self):
- space = self.space
-
- w_res = space.appexec([], """():
- import _stackless as stackless
- import pickle
- import new, sys
-
- mod = new.module('mod')
- sys.modules['mod'] = mod
-
- main = stackless.coroutine.getcurrent()
- d = {'main': main}
-
- exec \"\"\"
-def f():
- a = A()
- a.m(1)
-
-def g(_, x):
- main.switch()
-
-class A(object):
- m = g
-\"\"\" in d
- f = d['f']
- g = d['g']
- A = d['A']
-
- # to make pickling work
- mod.A = A
- A.__module__ = 'mod'
-
- co = stackless.coroutine()
- co.bind(f)
- co.switch()
-
- s = pickle.dumps(co)
- co = pickle.loads(s)
-
- return co, f, g
- """)
-
- w_co, w_f, w_g = space.fixedview(w_res)
-
- ec = space.getexecutioncontext()
- fcode = w_f.code.co_code
- gcode = w_g.code.co_code
-
- self.start(w_co)
- e = self.check_entry
- e('yield_current_frame_to_caller_1')
- e('coroutine__bind', w_co.costate)
- e('appthunk', w_co.costate)
- # f
- e('execute_frame', FrameCheck('f'), ec)
- e('dispatch', FrameCheck('f'), fcode, ec)
- e('handle_bytecode', FrameCheck('f'), fcode, ec)
- e('dispatch_call', FrameCheck('f'), fcode,
- BytecodeCheck(fcode, self.callmethod, 1), ec)
- e(self.callmethod_label, FrameCheck('f'), 1)
- # g
- e('execute_frame', FrameCheck('g'), ec)
- e('dispatch', FrameCheck('g'), gcode, ec)
- e('handle_bytecode', FrameCheck('g'), gcode, ec)
- e('dispatch_call', FrameCheck('g'), gcode,
- BytecodeCheck(gcode, self.callmethod, 0), ec)
- e(self.callmethod_label, FrameCheck('g'), 0)
- e('w_switch', w_co.costate, space)
- e('coroutine_switch', w_co.costate)
- self.end()
-
-class TestReconstructFrameChain(BaseTestReconstructFrameChain):
- callmethod_label = 'CALL_FUNCTION'
-
-class TestReconstructFrameChain_CALL_METHOD(BaseTestReconstructFrameChain):
- OPTIONS = {"objspace.opcodes.CALL_METHOD": True,
- }
-
- callmethod_label = 'CALL_METHOD'
-
-
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,9 +1,10 @@
import py
+from pypy.interpreter.argument import Arguments
from pypy.interpreter.baseobjspace import Wrappable, W_Root
-from pypy.interpreter.argument import Arguments
from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app, ObjSpace
from pypy.interpreter.typedef import GetSetProperty, TypeDef
-from pypy.interpreter.gateway import interp2app, ObjSpace
+from pypy.rlib import jit
import weakref
@@ -13,7 +14,7 @@
self.refs_weak = []
self.cached_weakref_index = -1
self.cached_proxy_index = -1
-
+
def __del__(self):
"""This runs when the interp-level object goes away, and allows
its lifeline to go away. The purpose of this is to activate the
@@ -37,6 +38,7 @@
# weakref callbacks are not invoked eagerly here. They are
# invoked by self.__del__() anyway.
+ @jit.dont_look_inside
def get_or_make_weakref(self, space, w_subtype, w_obj, w_callable):
w_weakreftype = space.gettypeobject(W_Weakref.typedef)
is_weakreftype = space.is_w(w_weakreftype, w_subtype)
@@ -55,6 +57,7 @@
self.cached_weakref_index = index
return w_ref
+ @jit.dont_look_inside
def get_or_make_proxy(self, space, w_obj, w_callable):
can_reuse = space.is_w(w_callable, space.w_None)
if can_reuse and self.cached_proxy_index >= 0:
@@ -81,7 +84,7 @@
w_weakreftype = space.gettypeobject(W_Weakref.typedef)
for i in range(len(self.refs_weak)):
w_ref = self.refs_weak[i]()
- if (w_ref is not None and
+ if (w_ref is not None and
space.is_true(space.isinstance(w_ref, w_weakreftype))):
return w_ref
return space.w_None
@@ -106,6 +109,7 @@
w_self.w_obj_weak = weakref.ref(w_obj)
w_self.w_callable = w_callable
+ @jit.dont_look_inside
def dereference(self):
w_obj = self.w_obj_weak()
return w_obj
@@ -244,7 +248,7 @@
lifeline = w_obj.getweakref()
if lifeline is None:
lifeline = WeakrefLifeline(space)
- w_obj.setweakref(space, lifeline)
+ w_obj.setweakref(space, lifeline)
return lifeline.get_or_make_proxy(space, w_obj, w_callable)
def descr__new__proxy(space, w_subtype, w_obj, w_callable=None):
diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py
--- a/pypy/module/bz2/interp_bz2.py
+++ b/pypy/module/bz2/interp_bz2.py
@@ -363,42 +363,44 @@
def seek(self, offset, whence):
READMAX = 2**18 # 256KB
- if whence == 1:
- if offset >= 0:
- read = r_longlong(0)
- while read < offset:
- count = offset - read
- if count < READMAX:
- count = intmask(count)
- else:
- count = READMAX
- read += len(self.read(count))
- else:
- pos = self.readlength + offset
- self.seek(pos, 0)
+
+ # Make offset relative to the start of the file
+ if whence == 2:
+ # Read everything to arrive at the end
+ while len(self.read(READMAX)) > 0:
+ pass
+ offset += self.readlength
+ elif whence == 1:
+ offset += self.readlength
elif whence == 0:
+ pass
+ else:
+ raise operationerrfmt(self.space.w_ValueError,
+ "Invalid value for whence: %d", whence)
+
+ # Make offset relative to the current pos
+ # Rewind iff necessary
+ if offset < self.readlength:
self.stream.seek(0, 0)
self.decompressor = W_BZ2Decompressor(self.space)
self.readlength = r_longlong(0)
self.buffer = ""
self.finished = False
- read = 0
- while read < offset:
- count = offset - read
- if count < READMAX:
- count = intmask(count)
- else:
- count = READMAX
- length = len(self.read(count))
- read += length
- if not length:
- break
else:
- # first measure the length by reading everything left
- while len(self.read(READMAX)) > 0:
- pass
- pos = self.readlength + offset
- self.seek(pos, 0)
+ offset -= self.readlength
+
+ # Seek
+ read = r_longlong(0)
+ while read < offset:
+ count = offset - read
+ if count < READMAX:
+ count = intmask(count)
+ else:
+ count = READMAX
+ length = len(self.read(count))
+ if not length:
+ break
+ read += length
def readall(self):
w_result = self.decompressor.decompress(self.stream.readall())
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
@@ -561,6 +561,7 @@
elif callable.api_func.restype is not lltype.Void:
retval = rffi.cast(callable.api_func.restype, result)
except Exception, e:
+ print 'Fatal error in cpyext, calling', callable.__name__
if not we_are_translated():
import traceback
traceback.print_exc()
@@ -965,6 +966,7 @@
state = space.fromcache(State)
if state.find_extension(name, path) is not None:
return
+ old_context = state.package_context
state.package_context = name, path
try:
from pypy.rlib import rdynload
@@ -990,7 +992,7 @@
generic_cpy_call(space, initfunc)
state.check_and_raise_exception()
finally:
- state.package_context = None, None
+ state.package_context = old_context
state.fixup_extension(name, path)
@specialize.ll()
diff --git a/pypy/module/cpyext/classobject.py b/pypy/module/cpyext/classobject.py
--- a/pypy/module/cpyext/classobject.py
+++ b/pypy/module/cpyext/classobject.py
@@ -31,4 +31,9 @@
return w_result
return w_instance.w_class.lookup(space, name)
+ at cpython_api([PyObject, PyObject, PyObject], PyObject)
+def PyClass_New(space, w_bases, w_dict, w_name):
+ w_classobj = space.gettypefor(W_ClassObject)
+ return space.call_function(w_classobj,
+ w_name, w_bases, w_dict)
diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py
--- a/pypy/module/cpyext/frameobject.py
+++ b/pypy/module/cpyext/frameobject.py
@@ -1,6 +1,7 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
- cpython_api, bootstrap_function, PyObjectFields, cpython_struct)
+ cpython_api, bootstrap_function, PyObjectFields, cpython_struct,
+ CANNOT_FAIL)
from pypy.module.cpyext.pyobject import (
PyObject, Py_DecRef, make_ref, from_ref, track_reference,
make_typedescr, get_typedescr)
@@ -9,6 +10,7 @@
from pypy.module.cpyext.funcobject import PyCodeObject
from pypy.interpreter.pyframe import PyFrame
from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.pytraceback import PyTraceback
PyFrameObjectStruct = lltype.ForwardReference()
PyFrameObject = lltype.Ptr(PyFrameObjectStruct)
@@ -80,3 +82,8 @@
frame = space.interp_w(PyFrame, w_frame)
record_application_traceback(space, state.operror, frame, 0)
return 0
+
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def PyTraceBack_Check(space, w_obj):
+ obj = space.interpclass_w(w_obj)
+ return obj is not None and isinstance(obj, PyTraceback)
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -69,6 +69,10 @@
assert isinstance(w_method, Method)
return borrow_from(w_method, w_method.w_class)
+ at cpython_api([PyObject], PyObject)
+def PyClassMethod_New(space, w_function):
+ return space.call_method(space.builtin, "classmethod", w_function)
+
def unwrap_list_of_strings(space, w_list):
return [space.str_w(w_item) for w_item in space.fixedview(w_list)]
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -4,7 +4,7 @@
from pypy.module.cpyext.api import (
cpython_api, build_type_checkers, PyObject,
CONST_STRING, CANNOT_FAIL, Py_ssize_t)
-from pypy.rlib.rarithmetic import r_uint
+from pypy.rlib.rarithmetic import r_uint, intmask, LONG_TEST
import sys
PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
@@ -73,13 +73,22 @@
space.wrap("an integer is required, got NULL"))
return space.int_w(w_obj) # XXX this is wrong on win64
+ at cpython_api([rffi.SIZE_T], PyObject)
+def PyInt_FromSize_t(space, ival):
+ """Create a new integer object with a value of ival. If the value exceeds
+ LONG_MAX, a long integer object is returned.
+ """
+ if ival < LONG_TEST:
+ return space.wrap(intmask(ival))
+ return space.wrap(ival)
+
@cpython_api([Py_ssize_t], PyObject)
def PyInt_FromSsize_t(space, ival):
"""Create a new integer object with a value of ival. If the value is larger
than LONG_MAX or smaller than LONG_MIN, a long integer object is
returned.
"""
- return space.wrap(ival) # XXX this is wrong on win64
+ return space.wrap(ival)
@cpython_api([CONST_STRING, rffi.CCHARPP, rffi.INT_real], PyObject)
def PyInt_FromString(space, str, pend, base):
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -73,29 +73,29 @@
rffi.charp2str(self.ml.c_ml_name) + "() takes no keyword arguments"))
func = rffi.cast(PyCFunction, self.ml.c_ml_meth)
+ length = space.int_w(space.len(w_args))
if flags & METH_KEYWORDS:
func = rffi.cast(PyCFunctionKwArgs, self.ml.c_ml_meth)
return generic_cpy_call(space, func, w_self, w_args, w_kw)
elif flags & METH_NOARGS:
- if len(w_args.wrappeditems) == 0:
+ if length == 0:
return generic_cpy_call(space, func, w_self, None)
raise OperationError(space.w_TypeError, space.wrap(
rffi.charp2str(self.ml.c_ml_name) + "() takes no arguments"))
elif flags & METH_O:
- assert isinstance(w_args, W_TupleObject)
- if len(w_args.wrappeditems) != 1:
+ if length != 1:
raise OperationError(space.w_TypeError,
space.wrap("%s() takes exactly one argument (%d given)" % (
rffi.charp2str(self.ml.c_ml_name),
- len(w_args.wrappeditems))))
- w_arg = w_args.wrappeditems[0]
+ length)))
+ w_arg = space.getitem(w_args, space.wrap(0))
return generic_cpy_call(space, func, w_self, w_arg)
elif flags & METH_VARARGS:
return generic_cpy_call(space, func, w_self, w_args)
else: # METH_OLDARGS, the really old style
- size = len(w_args.wrappeditems)
+ size = length
if size == 1:
- w_arg = w_args.wrappeditems[0]
+ w_arg = space.getitem(w_args, space.wrap(0))
elif size == 0:
w_arg = None
else:
diff --git a/pypy/module/cpyext/number.py b/pypy/module/cpyext/number.py
--- a/pypy/module/cpyext/number.py
+++ b/pypy/module/cpyext/number.py
@@ -49,6 +49,13 @@
failure. This is the equivalent of the Python expression long(o)."""
return space.long(w_obj)
+ at cpython_api([PyObject], PyObject)
+def PyNumber_Index(space, w_obj):
+ """Returns the o converted to a Python int or long on success or NULL with a
+ TypeError exception raised on failure.
+ """
+ return space.index(w_obj)
+
def func_rename(newname):
return lambda func: func_with_new_name(func, newname)
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -57,7 +57,7 @@
if operror:
ptype[0] = make_ref(space, operror.w_type)
pvalue[0] = make_ref(space, operror.get_w_value(space))
- ptraceback[0] = make_ref(space, space.wrap(operror.application_traceback))
+ ptraceback[0] = make_ref(space, space.wrap(operror.get_traceback()))
else:
ptype[0] = lltype.nullptr(PyObject.TO)
pvalue[0] = lltype.nullptr(PyObject.TO)
@@ -268,7 +268,7 @@
w_type = operror.w_type
w_value = operror.get_w_value(space)
- w_tb = space.wrap(operror.application_traceback)
+ w_tb = space.wrap(operror.get_traceback())
if rffi.cast(lltype.Signed, set_sys_last_vars):
space.sys.setdictvalue(space, "last_type", w_type)
diff --git a/pypy/module/cpyext/src/modsupport.c b/pypy/module/cpyext/src/modsupport.c
--- a/pypy/module/cpyext/src/modsupport.c
+++ b/pypy/module/cpyext/src/modsupport.c
@@ -611,8 +611,8 @@
if (result != NULL && n > 0) {
for (i = 0; i < n; ++i) {
tmp = (PyObject *)va_arg(va, PyObject *);
+ Py_INCREF(tmp);
PyTuple_SET_ITEM(result, i, tmp);
- Py_INCREF(tmp);
}
}
return result;
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
@@ -2,7 +2,7 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
- PyObjectFields, Py_ssize_t, CONST_STRING)
+ PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
from pypy.module.cpyext.pyerrors import PyErr_BadArgument
from pypy.module.cpyext.pyobject import (
PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
@@ -203,6 +203,10 @@
ref[0] = rffi.cast(PyObject, py_newstr)
return 0
+ at cpython_api([PyObject, PyObject], rffi.INT, error=CANNOT_FAIL)
+def _PyString_Eq(space, w_str1, w_str2):
+ return space.eq_w(w_str1, w_str2)
+
@cpython_api([PyObjectP, PyObject], lltype.Void)
def PyString_Concat(space, ref, w_newpart):
"""Create a new string object in *string containing the contents of newpart
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -172,12 +172,6 @@
This is equivalent to (PyBUF_ND)."""
raise NotImplementedError
- at cpython_api([Py_buffer], lltype.Void)
-def PyBuffer_Release(space, view):
- """Release the buffer view. This should be called when the buffer
- is no longer being used as it may free memory from it."""
- raise NotImplementedError
-
@cpython_api([rffi.CCHARP], Py_ssize_t, error=CANNOT_FAIL)
def PyBuffer_SizeFromFormat(space, format):
"""Return the implied ~Py_buffer.itemsize from the struct-stype
@@ -198,13 +192,6 @@
given shape with the given number of bytes per element."""
raise NotImplementedError
- at cpython_api([Py_buffer, PyObject, rffi.VOIDP, Py_ssize_t, rffi.INT_real, rffi.INT_real], rffi.INT_real, error=-1)
-def PyBuffer_FillInfo(space, view, obj, buf, len, readonly, infoflags):
- """Fill in a buffer-info structure, view, correctly for an exporter that can
- only share a contiguous chunk of memory of "unsigned bytes" of the given
- length. Return 0 on success and -1 (with raising an error) on error."""
- raise NotImplementedError
-
@cpython_api([Py_buffer], PyObject)
def PyMemoryView_FromBuffer(space, view):
"""Create a memoryview object wrapping the given buffer-info structure view.
@@ -1094,14 +1081,6 @@
"""
raise NotImplementedError
- at cpython_api([PyObject], PyObject)
-def PyImport_ReloadModule(space, m):
- """Reload a module. This is best described by referring to the built-in
- Python function reload(), as the standard reload() function calls this
- function directly. Return a new reference to the reloaded module, or NULL
- with an exception set on failure (the module still exists in this case)."""
- raise NotImplementedError
-
@cpython_api([rffi.CCHARP, PyObject], PyObject)
def PyImport_ExecCodeModule(space, name, co):
"""Given a module name (possibly of the form package.module) and a code
@@ -1140,13 +1119,6 @@
of the bytecode file, in little-endian byte order."""
raise NotImplementedError
- at cpython_api([], PyObject)
-def PyImport_GetModuleDict(space):
- """Return the dictionary used for the module administration (a.k.a.
- sys.modules). Note that this is a per-interpreter variable."""
- borrow_from()
- raise NotImplementedError
-
@cpython_api([PyObject], PyObject)
def PyImport_GetImporter(space, path):
"""Return an importer object for a sys.path/pkg.__path__ item
@@ -1701,13 +1673,6 @@
"""
raise NotImplementedError
- at cpython_api([rffi.SIZE_T], PyObject)
-def PyInt_FromSize_t(space, ival):
- """Create a new integer object with a value of ival. If the value exceeds
- LONG_MAX, a long integer object is returned.
- """
- raise NotImplementedError
-
@cpython_api([PyObject], rffi.ULONGLONG, error=-1)
def PyInt_AsUnsignedLongLongMask(space, io):
"""Will first attempt to cast the object to a PyIntObject or
@@ -1920,13 +1885,6 @@
Reference counts are still not increased in this case."""
raise NotImplementedError
- at cpython_api([PyObject], PyObject)
-def PyNumber_Index(space, o):
- """Returns the o converted to a Python int or long on success or NULL with a
- TypeError exception raised on failure.
- """
- raise NotImplementedError
-
@cpython_api([PyObject, rffi.INT_real], PyObject)
def PyNumber_ToBase(space, n, base):
"""Returns the integer n converted to base as a string with a base
@@ -2254,15 +2212,6 @@
standard C library function exit(status)."""
raise NotImplementedError
- at cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject)
-def PyTuple_GetSlice(space, p, low, high):
- """Take a slice of the tuple pointed to by p from low to high and return it
- as a new tuple.
-
- This function used an int type for low and high. This might
- require changes in your code for properly supporting 64-bit systems."""
- raise NotImplementedError
-
@cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
def PyTuple_ClearFreeList(space):
"""Clear the free list. Return the total number of freed items.
@@ -2275,14 +2224,6 @@
"""
raise NotImplementedError
- at cpython_api([PyTypeObjectPtr], lltype.Void)
-def PyType_Modified(space, type):
- """Invalidate the internal lookup cache for the type and all of its
- subtypes. This function must be called after any manual
- modification of the attributes or base classes of the type.
- """
- raise NotImplementedError
-
@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyType_IS_GC(space, o):
"""Return true if the type object includes support for the cycle detector; this
diff --git a/pypy/module/cpyext/test/test_classobject.py b/pypy/module/cpyext/test/test_classobject.py
--- a/pypy/module/cpyext/test/test_classobject.py
+++ b/pypy/module/cpyext/test/test_classobject.py
@@ -40,3 +40,14 @@
assert not isinstance(api.PyObject_GetAttr(w_instance, space.wrap('f')), Function)
# _PyInstance_Lookup returns the raw descriptor
assert isinstance(api._PyInstance_Lookup(w_instance, space.wrap('f')), Function)
+
+ def test_pyclass_new(self, space, api):
+ w_bases = space.newtuple([])
+ w_dict = space.newdict()
+ w_name = space.wrap("C")
+ w_class = api.PyClass_New(w_bases, w_dict, w_name)
+ assert not space.isinstance_w(w_class, space.w_type)
+ w_instance = space.call_function(w_class)
+ assert api.PyInstance_Check(w_instance)
+ assert space.is_true(space.call_method(space.builtin, "isinstance",
+ w_instance, w_class))
diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py
--- a/pypy/module/cpyext/test/test_eval.py
+++ b/pypy/module/cpyext/test/test_eval.py
@@ -193,3 +193,32 @@
return args
assert module.call_func(f) == ("text", 42, None)
assert module.call_method("text") == 2
+
+ def test_CallFunctionObjArgs(self):
+ module = self.import_extension('foo', [
+ ("call_func", "METH_VARARGS",
+ """
+ PyObject *t = PyString_FromString("t");
+ PyObject *res = PyObject_CallFunctionObjArgs(
+ PyTuple_GetItem(args, 0),
+ Py_None, NULL);
+ Py_DECREF(t);
+ return res;
+ """),
+ ("call_method", "METH_VARARGS",
+ """
+ PyObject *t = PyString_FromString("t");
+ PyObject *count = PyString_FromString("count");
+ PyObject *res = PyObject_CallMethodObjArgs(
+ PyTuple_GetItem(args, 0),
+ count, t, NULL);
+ Py_DECREF(t);
+ Py_DECREF(count);
+ return res;
+ """),
+ ])
+ def f(*args):
+ return args
+ assert module.call_func(f) == (None,)
+ assert module.call_method("text") == 2
+
diff --git a/pypy/module/cpyext/test/test_frameobject.py b/pypy/module/cpyext/test/test_frameobject.py
--- a/pypy/module/cpyext/test/test_frameobject.py
+++ b/pypy/module/cpyext/test/test_frameobject.py
@@ -64,3 +64,31 @@
# Cython does not work on CPython as well...
assert exc.traceback.tb_lineno == 42 # should be 48
assert frame.f_lineno == 42
+
+ def test_traceback_check(self):
+ module = self.import_extension('foo', [
+ ("traceback_check", "METH_NOARGS",
+ """
+ int check;
+ PyObject *type, *value, *tb;
+ PyObject *ret = PyRun_String("XXX", Py_eval_input,
+ Py_None, Py_None);
+ if (ret) {
+ Py_DECREF(ret);
+ PyErr_SetString(PyExc_AssertionError, "should raise");
+ return NULL;
+ }
+ PyErr_Fetch(&type, &value, &tb);
+ check = PyTraceBack_Check(tb);
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(tb);
+ if (check) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+ """),
+ ])
+ assert module.traceback_check()
diff --git a/pypy/module/cpyext/test/test_funcobject.py b/pypy/module/cpyext/test/test_funcobject.py
--- a/pypy/module/cpyext/test/test_funcobject.py
+++ b/pypy/module/cpyext/test/test_funcobject.py
@@ -44,3 +44,19 @@
assert w_code.co_firstlineno == 3
rffi.free_charp(filename)
rffi.free_charp(funcname)
+
+ def test_classmethod(self, space, api):
+ w_function = space.appexec([], """():
+ def method(x): return x
+ return method
+ """)
+ w_class = space.call_function(space.w_type, space.wrap("C"),
+ space.newtuple([]), space.newdict())
+ w_instance = space.call_function(w_class)
+ # regular instance method
+ space.setattr(w_class, space.wrap("method"), w_function)
+ assert space.is_w(space.call_method(w_instance, "method"), w_instance)
+ # now a classmethod
+ w_classmethod = api.PyClassMethod_New(w_function)
+ space.setattr(w_class, space.wrap("classmethod"), w_classmethod)
+ assert space.is_w(space.call_method(w_instance, "classmethod"), w_class)
diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py
--- a/pypy/module/cpyext/test/test_intobject.py
+++ b/pypy/module/cpyext/test/test_intobject.py
@@ -50,3 +50,19 @@
])
assert module.from_string() == 0x1234
assert type(module.from_string()) is int
+
+ def test_size_t(self):
+ module = self.import_extension('foo', [
+ ("values", "METH_NOARGS",
+ """
+ return Py_BuildValue("NNNN",
+ PyInt_FromSize_t(123),
+ PyInt_FromSize_t((size_t)-1),
+ PyInt_FromSsize_t(123),
+ PyInt_FromSsize_t((size_t)-1));
+ """),
+ ])
+ values = module.values()
+ types = [type(x) for x in values]
+ assert types == [int, long, int, int]
+
diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py
--- a/pypy/module/cpyext/test/test_number.py
+++ b/pypy/module/cpyext/test/test_number.py
@@ -25,6 +25,15 @@
assert api.PyInt_CheckExact(w_l)
w_l = api.PyNumber_Int(space.wrap(2 << 65))
assert api.PyLong_CheckExact(w_l)
+ w_l = api.PyNumber_Int(space.wrap(42.3))
+ assert api.PyInt_CheckExact(w_l)
+
+ def test_number_index(self, space, api):
+ w_l = api.PyNumber_Index(space.wrap(123L))
+ assert api.PyLong_CheckExact(w_l)
+ w_l = api.PyNumber_Index(space.wrap(42.3))
+ assert w_l is None
+ api.PyErr_Clear()
def test_numbermethods(self, space, api):
assert "ab" == space.unwrap(
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
@@ -283,3 +283,7 @@
self.raises(space, api, TypeError, api.PyString_AsEncodedObject,
space.wrap(2), lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO)
)
+
+ 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"))
diff --git a/pypy/module/cpyext/test/test_sysmodule.py b/pypy/module/cpyext/test/test_sysmodule.py
--- a/pypy/module/cpyext/test/test_sysmodule.py
+++ b/pypy/module/cpyext/test/test_sysmodule.py
@@ -22,12 +22,13 @@
Py_RETURN_NONE;
""")])
import sys, StringIO
+ prev = sys.stdout
sys.stdout = StringIO.StringIO()
try:
module.writestdout()
assert sys.stdout.getvalue() == "format: 42\n"
finally:
- sys.stdout = sys.__stdout__
+ sys.stdout = prev
class TestSysModule(BaseApiTest):
def test_sysmodule(self, space, api):
diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -3,8 +3,10 @@
from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.conftest import gettestobjspace
class TestTupleObject(BaseApiTest):
+
def test_tupleobject(self, space, api):
assert not api.PyTuple_Check(space.w_None)
assert api.PyTuple_SetItem(space.w_None, 0, space.w_None) == -1
@@ -20,11 +22,29 @@
ar[0] = rffi.cast(PyObject, make_ref(space, py_tuple))
api._PyTuple_Resize(ar, 2)
py_tuple = from_ref(space, ar[0])
- assert len(py_tuple.wrappeditems) == 2
+ assert space.int_w(space.len(py_tuple)) == 2
api._PyTuple_Resize(ar, 10)
py_tuple = from_ref(space, ar[0])
- assert len(py_tuple.wrappeditems) == 10
+ assert space.int_w(space.len(py_tuple)) == 10
api.Py_DecRef(ar[0])
lltype.free(ar, flavor='raw')
+
+ def test_setitem(self, space, api):
+ atuple = space.newtuple([space.wrap(0), space.wrap("hello")])
+ assert api.PyTuple_Size(atuple) == 2
+ assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0))
+ assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap("hello"))
+ w_obj = space.wrap(1)
+ api.Py_IncRef(w_obj)
+ api.PyTuple_SetItem(atuple, 1, w_obj)
+ assert api.PyTuple_Size(atuple) == 2
+ assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0))
+ assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap(1))
+
+ def test_getslice(self, space, api):
+ w_tuple = space.newtuple([space.wrap(i) for i in range(10)])
+ w_slice = api.PyTuple_GetSlice(w_tuple, 3, -3)
+ assert space.eq_w(w_slice,
+ space.newtuple([space.wrap(i) for i in range(3, 7)]))
diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -6,7 +6,7 @@
borrow_from, make_ref, from_ref)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.objspace.std.tupleobject import W_TupleObject
-
+from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple")
@@ -19,25 +19,30 @@
if not PyTuple_Check(space, w_t):
# XXX this should also steal a reference, test it!!!
PyErr_BadInternalCall(space)
- assert isinstance(w_t, W_TupleObject)
- w_t.wrappeditems[pos] = w_obj
+ _setitem_tuple(w_t, pos, w_obj)
Py_DecRef(space, w_obj) # SetItem steals a reference!
return 0
+def _setitem_tuple(w_t, pos, w_obj):
+ if isinstance(w_t, W_TupleObject):
+ w_t.wrappeditems[pos] = w_obj
+ elif isinstance(w_t, W_SmallTupleObject):
+ w_t.setitem(pos, w_obj)
+ else:
+ assert False
+
@cpython_api([PyObject, Py_ssize_t], PyObject)
def PyTuple_GetItem(space, w_t, pos):
if not PyTuple_Check(space, w_t):
PyErr_BadInternalCall(space)
- assert isinstance(w_t, W_TupleObject)
- w_obj = w_t.wrappeditems[pos]
+ w_obj = space.getitem(w_t, space.wrap(pos))
return borrow_from(w_t, w_obj)
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
def PyTuple_GET_SIZE(space, w_t):
"""Return the size of the tuple p, which must be non-NULL and point to a tuple;
no error checking is performed. """
- assert isinstance(w_t, W_TupleObject)
- return len(w_t.wrappeditems)
+ return space.int_w(space.len(w_t))
@cpython_api([PyObject], Py_ssize_t, error=-1)
def PyTuple_Size(space, ref):
@@ -63,15 +68,21 @@
py_tuple = from_ref(space, ref[0])
if not PyTuple_Check(space, py_tuple):
PyErr_BadInternalCall(space)
- assert isinstance(py_tuple, W_TupleObject)
py_newtuple = PyTuple_New(space, newsize)
to_cp = newsize
- oldsize = len(py_tuple.wrappeditems)
+ oldsize = space.int_w(space.len(py_tuple))
if oldsize < newsize:
to_cp = oldsize
for i in range(to_cp):
- py_newtuple.wrappeditems[i] = py_tuple.wrappeditems[i]
+ _setitem_tuple(py_newtuple, i, space.getitem(py_tuple, space.wrap(i)))
Py_DecRef(space, ref[0])
ref[0] = make_ref(space, py_newtuple)
return 0
+
+ at cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject)
+def PyTuple_GetSlice(space, w_obj, low, high):
+ """Take a slice of the tuple pointed to by p from low to high and return it
+ as a new tuple.
+ """
+ return space.getslice(w_obj, space.wrap(low), space.wrap(high))
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -650,3 +650,13 @@
name = space.str_w(w_name)
w_obj = w_type.lookup(name)
return borrow_from(w_type, w_obj)
+
+ at cpython_api([PyTypeObjectPtr], lltype.Void)
+def PyType_Modified(space, w_obj):
+ """Invalidate the internal lookup cache for the type and all of its
+ subtypes. This function must be called after any manual
+ modification of the attributes or base classes of the type.
+ """
+ # PyPy already takes care of direct modifications to type.__dict__
+ # (which is a W_DictProxyObject).
+ pass
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
@@ -1,13 +1,23 @@
-from pypy.interpreter.mixedmodule import MixedModule
+from pypy.interpreter.mixedmodule import MixedModule
class Module(MixedModule):
applevel_name = 'numpy'
-
+
interpleveldefs = {
- 'zeros' : 'numarray.zeros',
- 'minimum' : 'ufunc.minimum',
- }
+ 'array': 'interp_numarray.SingleDimArray',
+ 'zeros': 'interp_numarray.zeros',
+
+ # ufuncs
+ 'absolute': 'interp_ufuncs.absolute',
+ 'copysign': 'interp_ufuncs.copysign',
+ 'exp': 'interp_ufuncs.exp',
+ 'maximum': 'interp_ufuncs.maximum',
+ 'minimum': 'interp_ufuncs.minimum',
+ 'negative': 'interp_ufuncs.negative',
+ 'reciprocal': 'interp_ufuncs.reciprocal',
+ 'sign': 'interp_ufuncs.sign',
+ }
appleveldefs = {}
diff --git a/pypy/module/micronumpy/bench/add.py b/pypy/module/micronumpy/bench/add.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/bench/add.py
@@ -0,0 +1,10 @@
+
+import numpy
+
+def f():
+ a = numpy.zeros(10000000)
+ a = a + a + a + a + a
+ # To ensure that the computation isn't totally optimized away.
+ a[0] = 3.0
+
+f()
diff --git a/pypy/module/micronumpy/bench/iterate.py b/pypy/module/micronumpy/bench/iterate.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/bench/iterate.py
@@ -0,0 +1,11 @@
+
+import numpy
+
+def f():
+ sum = 0
+ a = numpy.zeros(10000000)
+ for i in range(10000000):
+ sum += a[i]
+ return sum
+
+f()
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -0,0 +1,257 @@
+from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
+from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rlib import jit
+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
+
+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
+
+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
+
+class BaseArray(Wrappable):
+ def __init__(self):
+ self.invalidates = []
+
+ def invalidated(self):
+ for arr in self.invalidates:
+ arr.force_if_needed()
+ self.invalidates = []
+
+ def _binop_impl(function):
+ signature = Signature()
+ 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__)
+
+ descr_add = _binop_impl(add)
+ descr_sub = _binop_impl(sub)
+ descr_mul = _binop_impl(mul)
+ descr_div = _binop_impl(div)
+
+ def get_concrete(self):
+ raise NotImplementedError
+
+ def descr_len(self, space):
+ return self.get_concrete().descr_len(space)
+
+ @unwrap_spec(item=int)
+ def descr_getitem(self, space, item):
+ return self.get_concrete().descr_getitem(space, item)
+
+ @unwrap_spec(item=int, value=float)
+ def descr_setitem(self, space, item, value):
+ self.invalidated()
+ return self.get_concrete().descr_setitem(space, item, value)
+
+
+class FloatWrapper(BaseArray):
+ """
+ Intermediate class representing a float literal.
+ """
+ _immutable_fields_ = ["float_value"]
+ signature = Signature()
+
+ def __init__(self, float_value):
+ BaseArray.__init__(self)
+ self.float_value = float_value
+
+ def find_size(self):
+ raise ValueError
+
+ def eval(self, i):
+ return self.float_value
+
+class VirtualArray(BaseArray):
+ """
+ Class for representing virtual arrays, such as binary ops or ufuncs
+ """
+ def __init__(self, signature):
+ BaseArray.__init__(self)
+ self.forced_result = None
+ self.signature = signature
+
+ def compute(self):
+ i = 0
+ signature = self.signature
+ result_size = self.find_size()
+ result = SingleDimArray(result_size)
+ while i < result_size:
+ numpy_driver.jit_merge_point(signature=signature,
+ result_size=result_size, i=i,
+ self=self, result=result)
+ result.storage[i] = self.eval(i)
+ i += 1
+ return result
+
+ def force_if_needed(self):
+ if self.forced_result is None:
+ self.forced_result = self.compute()
+
+ def get_concrete(self):
+ self.force_if_needed()
+ return self.forced_result
+
+ def eval(self, i):
+ if self.forced_result is not None:
+ return self.forced_result.eval(i)
+ return self._eval(i)
+
+class Call1(VirtualArray):
+ _immutable_fields_ = ["function", "values"]
+
+ def __init__(self, function, values, signature):
+ VirtualArray.__init__(self, signature)
+ self.function = function
+ self.values = values
+
+ def find_size(self):
+ return self.values.find_size()
+
+ def _eval(self, i):
+ return self.function(self.values.eval(i))
+
+class Call2(VirtualArray):
+ """
+ Intermediate class for performing binary operations.
+ """
+ _immutable_fields_ = ["function", "left", "right"]
+ def __init__(self, function, left, right, signature):
+ VirtualArray.__init__(self, signature)
+ self.function = function
+ self.left = left
+ self.right = right
+
+ def find_size(self):
+ try:
+ return self.left.find_size()
+ except ValueError:
+ pass
+ return self.right.find_size()
+
+ def _eval(self, i):
+ lhs, rhs = self.left.eval(i), self.right.eval(i)
+ return self.function(lhs, rhs)
+
+
+class SingleDimArray(BaseArray):
+ signature = Signature()
+
+ def __init__(self, size):
+ BaseArray.__init__(self)
+ self.size = size
+ self.storage = lltype.malloc(TP, size, zero=True,
+ flavor='raw', track_allocation=False)
+ # XXX find out why test_zjit explodes with trackign of allocations
+
+ def get_concrete(self):
+ return self
+
+ 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)
+
+ @unwrap_spec(item=int)
+ def descr_getitem(self, space, item):
+ item = self.getindex(space, item)
+ return space.wrap(self.storage[item])
+
+ @unwrap_spec(item=int, value=float)
+ def descr_setitem(self, space, item, value):
+ item = self.getindex(space, item)
+ self.invalidated()
+ self.storage[item] = value
+
+ def __del__(self):
+ lltype.free(self.storage, flavor='raw')
+
+def descr_new_numarray(space, w_type, 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)
+
+ at unwrap_spec(ObjSpace, int)
+def zeros(space, size):
+ return space.wrap(SingleDimArray(size))
+
+
+BaseArray.typedef = TypeDef(
+ 'numarray',
+ __new__ = interp2app(descr_new_numarray),
+ __len__ = interp2app(BaseArray.descr_len),
+ __getitem__ = interp2app(BaseArray.descr_getitem),
+ __setitem__ = interp2app(BaseArray.descr_setitem),
+
+ __add__ = interp2app(BaseArray.descr_add),
+ __sub__ = interp2app(BaseArray.descr_sub),
+ __mul__ = interp2app(BaseArray.descr_mul),
+ __div__ = interp2app(BaseArray.descr_div),
+)
\ No newline at end of file
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -0,0 +1,66 @@
+import math
+
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature
+from pypy.rlib import rfloat
+from pypy.tool.sourcetools import func_with_new_name
+
+
+def ufunc(func):
+ signature = Signature()
+ @unwrap_spec(array=BaseArray)
+ def impl(space, array):
+ w_res = Call1(func, array, array.signature.transition(signature))
+ array.invalidates.append(w_res)
+ return w_res
+ return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
+
+def ufunc2(func):
+ signature = Signature()
+ @unwrap_spec(larray=BaseArray, rarray=BaseArray)
+ def impl(space, larray, rarray):
+ new_sig = larray.signature.transition(signature).transition(rarray.signature)
+ w_res = Call2(func, larray, rarray, new_sig)
+ larray.invalidates.append(w_res)
+ rarray.invalidates.append(w_res)
+ return w_res
+ return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
+
+ at ufunc
+def absolute(value):
+ return abs(value)
+
+ at ufunc2
+def copysign(lvalue, rvalue):
+ return rfloat.copysign(lvalue, rvalue)
+
+ at ufunc
+def exp(value):
+ try:
+ return math.exp(value)
+ except OverflowError:
+ return rfloat.INFINITY
+
+ at ufunc2
+def maximum(lvalue, rvalue):
+ return max(lvalue, rvalue)
+
+ at ufunc2
+def minimum(lvalue, rvalue):
+ return min(lvalue, rvalue)
+
+ at ufunc
+def negative(value):
+ return -value
+
+ at ufunc
+def reciprocal(value):
+ if value == 0.0:
+ return rfloat.copysign(rfloat.INFINITY, value)
+ return 1.0 / value
+
+ at ufunc
+def sign(value):
+ if value == 0.0:
+ return 0.0
+ return rfloat.copysign(1.0, value)
diff --git a/pypy/module/micronumpy/numarray.py b/pypy/module/micronumpy/numarray.py
deleted file mode 100644
--- a/pypy/module/micronumpy/numarray.py
+++ /dev/null
@@ -1,123 +0,0 @@
-
-from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
-from pypy.rlib.debug import make_sure_not_resized
-
-class BaseNumArray(Wrappable):
- pass
-
-class NumArray(BaseNumArray):
- def __init__(self, space, dim, dtype):
- self.dim = dim
- self.space = space
- # ignore dtype for now
- self.storage = [0] * dim
- make_sure_not_resized(self.storage)
-
- @unwrap_spec(index=int)
- def descr_getitem(self, index):
- space = self.space
- try:
- return space.wrap(self.storage[index])
- except IndexError:
- raise OperationError(space.w_IndexError,
- space.wrap("list index out of range"))
-
- @unwrap_spec(index=int, value=int)
- def descr_setitem(self, index, value):
- space = self.space
- try:
- self.storage[index] = value
- except IndexError:
- raise OperationError(space.w_IndexError,
- space.wrap("list index out of range"))
- return space.w_None
-
- def descr_len(self):
- return self.space.wrap(len(self.storage))
-
-NumArray.typedef = TypeDef(
- 'NumArray',
- __getitem__ = interp2app(NumArray.descr_getitem),
- __setitem__ = interp2app(NumArray.descr_setitem),
- __len__ = interp2app(NumArray.descr_len),
-)
-
-def compute_pos(space, indexes, dim):
- current = 1
- pos = 0
- for i in range(len(indexes)):
- index = indexes[i]
- d = dim[i]
- if index >= d or index <= -d - 1:
- raise OperationError(space.w_IndexError,
- space.wrap("invalid index"))
- if index < 0:
- index = d + index
- pos += index * current
- current *= d
- return pos
-
-class MultiDimArray(BaseNumArray):
- def __init__(self, space, dim, dtype):
- self.dim = dim
- self.space = space
- # ignore dtype for now
- size = 1
- for el in dim:
- size *= el
- self.storage = [0] * size
- make_sure_not_resized(self.storage)
-
- def _unpack_indexes(self, space, w_index):
- indexes = [space.int_w(w_i) for w_i in space.fixedview(w_index)]
- if len(indexes) != len(self.dim):
- raise OperationError(space.w_IndexError, space.wrap(
- 'Wrong index'))
- return indexes
-
- def descr_getitem(self, w_index):
- space = self.space
- indexes = self._unpack_indexes(space, w_index)
- pos = compute_pos(space, indexes, self.dim)
- return space.wrap(self.storage[pos])
-
- @unwrap_spec(value=int)
- def descr_setitem(self, w_index, value):
- space = self.space
- indexes = self._unpack_indexes(space, w_index)
- pos = compute_pos(space, indexes, self.dim)
- self.storage[pos] = value
- return space.w_None
-
- def descr_len(self):
- return self.space.wrap(self.dim[0])
-
-MultiDimArray.typedef = TypeDef(
- 'NumArray',
- __getitem__ = interp2app(MultiDimArray.descr_getitem),
- __setitem__ = interp2app(MultiDimArray.descr_setitem),
- __len__ = interp2app(MultiDimArray.descr_len),
-)
-
-def unpack_dim(space, w_dim):
- if space.is_true(space.isinstance(w_dim, space.w_int)):
- return [space.int_w(w_dim)]
- dim_w = space.fixedview(w_dim)
- return [space.int_w(w_i) for w_i in dim_w]
-
-def unpack_dtype(space, w_dtype):
- if space.is_w(w_dtype, space.w_int):
- return 'i'
- else:
- raise NotImplementedError
-
-def zeros(space, w_dim, w_dtype):
- dim = unpack_dim(space, w_dim)
- dtype = unpack_dtype(space, w_dtype)
- if len(dim) == 1:
- return space.wrap(NumArray(space, dim[0], dtype))
- else:
- return space.wrap(MultiDimArray(space, dim, dtype))
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -0,0 +1,19 @@
+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)
+ v1 = ar.descr_add(space, ar)
+ v2 = ar.descr_add(space, FloatWrapper(2.0))
+ assert v1.signature is not v2.signature
+ v3 = ar.descr_add(space, FloatWrapper(1.0))
+ assert v2.signature is v3.signature
+ v4 = ar.descr_add(space, ar)
+ assert v1.signature is v4.signature
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -0,0 +1,141 @@
+import py
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestNumArray(BaseNumpyAppTest):
+ def test_type(self):
+ from numpy import array
+ ar = array(range(5))
+ assert type(ar) is type(ar + ar)
+
+ def test_init(self):
+ from numpy import zeros
+ a = zeros(15)
+ # Check that storage was actually zero'd.
+ assert a[10] == 0.0
+ # And check that changes stick.
+ a[13] = 5.3
+ assert a[13] == 5.3
+
+ def test_iterator_init(self):
+ from numpy import array
+ a = array(range(5))
+ assert a[3] == 3
+
+ def test_getitem(self):
+ from numpy import array
+ a = array(range(5))
+ raises(IndexError, "a[5]")
+ a = a + a
+ raises(IndexError, "a[5]")
+ assert a[-1] == 8
+ raises(IndexError, "a[-6]")
+
+ def test_setitem(self):
+ from numpy import array
+ a = array(range(5))
+ a[-1] = 5.0
+ assert a[4] == 5.0
+ raises(IndexError, "a[5] = 0.0")
+ raises(IndexError, "a[-6] = 3.0")
+
+ def test_len(self):
+ from numpy import array
+ a = array(range(5))
+ assert len(a) == 5
+ assert len(a + a) == 5
+
+ def test_add(self):
+ from numpy import array
+ a = array(range(5))
+ b = a + a
+ for i in range(5):
+ assert b[i] == i + i
+
+ def test_add_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array(reversed(range(5)))
+ c = a + b
+ for i in range(5):
+ assert c[i] == 4
+
+ def test_add_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a + 5
+ for i in range(5):
+ assert b[i] == i + 5
+
+ def test_subtract(self):
+ from numpy import array
+ a = array(range(5))
+ b = a - a
+ for i in range(5):
+ assert b[i] == 0
+
+ def test_subtract_other(self):
+ from numpy import array
+ a = array(range(5))
+ b = array([1, 1, 1, 1, 1])
+ c = a - b
+ for i in range(5):
+ assert c[i] == i - 1
+
+ def test_subtract_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a - 5
+ for i in range(5):
+ assert b[i] == i - 5
+
+ def test_mul(self):
+ from numpy import array
+ a = array(range(5))
+ b = a * a
+ for i in range(5):
+ assert b[i] == i * i
+
+ def test_mul_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a * 5
+ for i in range(5):
+ assert b[i] == i * 5
+
+ def test_div(self):
+ from numpy import array
+ a = array(range(1, 6))
+ b = a / a
+ for i in range(5):
+ assert b[i] == 1
+
+ def test_div_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.0
+
+ def test_div_constant(self):
+ from numpy import array
+ a = array(range(5))
+ b = a / 5.0
+ for i in range(5):
+ assert b[i] == i / 5.0
+
+ def test_auto_force(self):
+ from numpy import array
+ a = array(range(5))
+ b = a - 1
+ a[2] = 3
+ for i in range(5):
+ assert b[i] == i - 1
+
+ a = array(range(5))
+ b = a + a
+ c = b + b
+ b[1] = 5
+ assert c[1] == 4
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_numpy.py b/pypy/module/micronumpy/test/test_numpy.py
deleted file mode 100644
--- a/pypy/module/micronumpy/test/test_numpy.py
+++ /dev/null
@@ -1,65 +0,0 @@
-
-from pypy.conftest import gettestobjspace
-
-class AppTestNumpy(object):
- def setup_class(cls):
- cls.space = gettestobjspace(usemodules=('micronumpy',))
-
- def test_zeroes(self):
- from numpy import zeros
- ar = zeros(3, dtype=int)
- assert ar[0] == 0
-
- def test_setitem_getitem(self):
- from numpy import zeros
- ar = zeros(8, dtype=int)
- assert ar[0] == 0
- ar[1] = 3
- assert ar[1] == 3
- raises((TypeError, ValueError), ar.__getitem__, 'xyz')
- raises(IndexError, ar.__getitem__, 38)
- assert ar[-2] == 0
- assert ar[-7] == 3
- assert len(ar) == 8
-
- def test_minimum(self):
- from numpy import zeros, minimum
- ar = zeros(5, dtype=int)
- ar2 = zeros(5, dtype=int)
- ar[0] = 3
- ar[1] = -3
- ar[2] = 8
- ar2[3] = -1
- ar2[4] = 8
- x = minimum(ar, ar2)
- assert x[0] == 0
- assert x[1] == -3
- assert x[2] == 0
- assert x[3] == -1
- assert x[4] == 0
- assert len(x) == 5
- raises(ValueError, minimum, ar, zeros(3, dtype=int))
-
-class AppTestMultiDim(object):
- def setup_class(cls):
- cls.space = gettestobjspace(usemodules=('micronumpy',))
-
- def test_multidim(self):
- from numpy import zeros
- ar = zeros((3, 3), dtype=int)
- assert ar[0, 2] == 0
- raises(IndexError, ar.__getitem__, (3, 0))
- assert ar[-2, 1] == 0
-
- def test_multidim_getset(self):
- from numpy import zeros
- ar = zeros((3, 3, 3), dtype=int)
- ar[1, 2, 1] = 3
- assert ar[1, 2, 1] == 3
- assert ar[-2, 2, 1] == 3
- assert ar[2, 2, 1] == 0
- assert ar[-2, 2, -2] == 3
-
- def test_len(self):
- from numpy import zeros
- assert len(zeros((3, 2, 1), dtype=int)) == 3
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -0,0 +1,85 @@
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestUfuncs(BaseNumpyAppTest):
+ def test_negative(self):
+ from numpy import array, negative
+
+ a = array([-5.0, 0.0, 1.0])
+ b = negative(a)
+ for i in range(3):
+ assert b[i] == -a[i]
+
+ a = array([-5.0, 1.0])
+ b = negative(a)
+ a[0] = 5.0
+ assert b[0] == 5.0
+
+ def test_abs(self):
+ from numpy import array, absolute
+
+ a = array([-5.0, -0.0, 1.0])
+ b = absolute(a)
+ for i in range(3):
+ assert b[i] == abs(a[i])
+
+ def test_minimum(self):
+ from numpy import array, minimum
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = minimum(a, b)
+ for i in range(3):
+ assert c[i] == min(a[i], b[i])
+
+ def test_maximum(self):
+ from numpy import array, maximum
+
+ a = array([-5.0, -0.0, 1.0])
+ b = array([ 3.0, -2.0,-3.0])
+ c = maximum(a, b)
+ for i in range(3):
+ assert c[i] == max(a[i], b[i])
+
+ def test_sign(self):
+ from numpy import array, sign
+
+ reference = [-1.0, 0.0, 0.0, 1.0]
+ a = array([-5.0, -0.0, 0.0, 6.0])
+ b = sign(a)
+ for i in range(4):
+ assert b[i] == reference[i]
+
+ def test_reciporocal(self):
+ from numpy import array, reciprocal
+
+ reference = [-0.2, float("inf"), float("-inf"), 2.0]
+ a = array([-5.0, 0.0, -0.0, 0.5])
+ b = reciprocal(a)
+ for i in range(4):
+ assert b[i] == reference[i]
+
+ def test_copysign(self):
+ from numpy import array, copysign
+
+ reference = [5.0, -0.0, 0.0, -6.0]
+ a = array([-5.0, 0.0, 0.0, 6.0])
+ b = array([5.0, -0.0, 3.0, -6.0])
+ c = copysign(a, b)
+ for i in range(4):
+ assert c[i] == reference[i]
+
+ def test_exp(self):
+ import math
+ from numpy import array, exp
+
+ a = array([-5.0, -0.0, 0.0, 12345678.0, float("inf"),
+ -float('inf'), -12343424.0])
+ b = exp(a)
+ for i in range(4):
+ try:
+ res = math.exp(a[i])
+ except OverflowError:
+ res = float('inf')
+ assert b[i] == res
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -0,0 +1,94 @@
+from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature,
+ FloatWrapper, Call1, Call2, add, mul)
+from pypy.module.micronumpy.interp_ufuncs import negative
+
+
+class FakeSpace(object):
+ pass
+
+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())
+ return v.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': 1,
+ 'int_lt': 1, 'guard_true': 1, 'jump': 1})
+ 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())
+ return v.get_concrete().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
+ "setarrayitem_raw": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1})
+ assert result == f(5)
+
+ def test_already_forecd(self):
+ space = self.space
+
+ 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()
+ return v2.get_concrete().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ # This is the sum of the ops for both loops, however if you remove the
+ # optimization then you end up with 2 float_adds, so we can still be
+ # sure it was optimized correctly.
+ self.check_loops({"getarrayitem_raw": 2, "float_mul": 1, "float_add": 1,
+ "setarrayitem_raw": 2, "int_add": 2,
+ "int_lt": 2, "guard_true": 2, "jump": 2})
+ assert result == f(5)
+
+ def test_ufunc(self):
+ space = self.space
+ def f(i):
+ ar = SingleDimArray(i)
+ v1 = Call2(add, ar, ar, Signature())
+ v2 = negative(space, v1)
+ return v2.get_concrete().storage[3]
+
+ result = self.meta_interp(f, [5], listops=True, backendopt=True)
+ self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1,
+ "setarrayitem_raw": 1, "int_add": 1,
+ "int_lt": 1, "guard_true": 1, "jump": 1,
+ })
+ assert result == f(5)
+
+ def test_appropriate_specialization(self):
+ space = self.space
+ def f(i):
+ add_sig = Signature()
+ mul_sig = Signature()
+ ar = SingleDimArray(i)
+
+ v1 = Call2(add, ar, ar, ar.signature.transition(add_sig))
+ v2 = negative(space, v1)
+ v2.get_concrete()
+
+ for i in xrange(5):
+ v1 = Call2(mul, ar, ar, ar.signature.transition(mul_sig))
+ v2 = negative(space, v1)
+ v2.get_concrete()
+
+ self.meta_interp(f, [5], listops=True, backendopt=True)
+ # This is 3, not 2 because there is a bridge for the exit.
+ self.check_loop_count(3)
\ No newline at end of file
diff --git a/pypy/module/micronumpy/ufunc.py b/pypy/module/micronumpy/ufunc.py
deleted file mode 100644
--- a/pypy/module/micronumpy/ufunc.py
+++ /dev/null
@@ -1,21 +0,0 @@
-
-from numarray import NumArray
-from pypy.interpreter.baseobjspace import ObjSpace, W_Root
-from pypy.interpreter.error import OperationError
-
-def minimum(space, w_a, w_b):
- if not isinstance(w_a, NumArray) or not isinstance(w_b, NumArray):
- raise OperationError(space.w_TypeError,
- space.wrap("expecting NumArrat object"))
- if w_a.dim != w_b.dim:
- raise OperationError(space.w_ValueError,
- space.wrap("minimum of arrays of different length"))
- res = NumArray(space, w_a.dim, 'i')
- for i in range(len(w_a.storage)):
- one = w_a.storage[i]
- two = w_b.storage[i]
- if one < two:
- res.storage[i] = one
- else:
- res.storage[i] = two
- return space.wrap(res)
diff --git a/pypy/module/oracle/__init__.py b/pypy/module/oracle/__init__.py
--- a/pypy/module/oracle/__init__.py
+++ b/pypy/module/oracle/__init__.py
@@ -28,6 +28,7 @@
appleveldefs = {
'version': 'app_oracle.version',
+ 'paramstyle': 'app_oracle.paramstyle',
'makedsn': 'app_oracle.makedsn',
'TimestampFromTicks': 'app_oracle.TimestampFromTicks',
}
diff --git a/pypy/module/oracle/app_oracle.py b/pypy/module/oracle/app_oracle.py
--- a/pypy/module/oracle/app_oracle.py
+++ b/pypy/module/oracle/app_oracle.py
@@ -1,4 +1,5 @@
version = '5.0.0'
+paramstyle = 'named'
class Warning(StandardError):
pass
diff --git a/pypy/module/oracle/config.py b/pypy/module/oracle/config.py
--- a/pypy/module/oracle/config.py
+++ b/pypy/module/oracle/config.py
@@ -16,6 +16,7 @@
return space.str_w(w_obj)
def w_string(space, buf, len=-1):
+ #assert type(len) is int
if len < 0:
return space.wrap(rffi.charp2str(buf))
else:
diff --git a/pypy/module/oracle/interp_connect.py b/pypy/module/oracle/interp_connect.py
--- a/pypy/module/oracle/interp_connect.py
+++ b/pypy/module/oracle/interp_connect.py
@@ -159,9 +159,20 @@
# set the internal and external names; these are needed for global
# transactions but are limited in terms of the lengths of the strings
if twophase:
- raise OperationError(
- interp_error.get(space).w_NotSupportedError,
- space.wrap("XXX write me"))
+ status = roci.OCIAttrSet(
+ self.serverHandle, roci.OCI_HTYPE_SERVER,
+ "cx_Oracle", 0,
+ roci.OCI_ATTR_INTERNAL_NAME,
+ self.environment.errorHandle)
+ self.environment.checkForError(
+ status, "Connection_Connect(): set internal name")
+ status = roci.OCIAttrSet(
+ self.serverHandle, roci.OCI_HTYPE_SERVER,
+ "cx_Oracle", 0,
+ roci.OCI_ATTR_EXTERNAL_NAME,
+ self.environment.errorHandle)
+ self.environment.checkForError(
+ status, "Connection_Connect(): set external name")
# allocate the session handle
handleptr = lltype.malloc(rffi.CArrayPtr(roci.OCISession).TO,
@@ -371,6 +382,7 @@
finally:
stringBuffer.clear()
lltype.free(foundptr, flavor='raw')
+ lltype.free(handleptr, flavor='raw')
# eliminate the authorization handle immediately, if applicable
if authInfo:
diff --git a/pypy/module/oracle/interp_cursor.py b/pypy/module/oracle/interp_cursor.py
--- a/pypy/module/oracle/interp_cursor.py
+++ b/pypy/module/oracle/interp_cursor.py
@@ -459,7 +459,7 @@
self.environment.checkForError(
status,
"Cursor_ItemDescription(): name")
- name = rffi.charpsize2str(nameptr[0], lenptr[0])
+ name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
finally:
lltype.free(nameptr, flavor='raw')
lltype.free(lenptr, flavor='raw')
diff --git a/pypy/module/oracle/interp_object.py b/pypy/module/oracle/interp_object.py
--- a/pypy/module/oracle/interp_object.py
+++ b/pypy/module/oracle/interp_object.py
@@ -38,7 +38,7 @@
self.environment.checkForError(
status,
"ObjectType_Initialize(): get schema name")
- self.schema = rffi.charpsize2str(nameptr[0], lenptr[0])
+ self.schema = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
# determine the name of the type
status = roci.OCIAttrGet(
@@ -50,7 +50,7 @@
self.environment.checkForError(
status,
"ObjectType_Initialize(): get schema name")
- self.name = rffi.charpsize2str(nameptr[0], lenptr[0])
+ self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
finally:
lltype.free(nameptr, flavor='raw')
lltype.free(lenptr, flavor='raw')
@@ -301,7 +301,7 @@
connection.environment.checkForError(
status,
"ObjectAttribute_Initialize(): get name")
- self.name = rffi.charpsize2str(nameptr[0], lenptr[0])
+ self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
finally:
lltype.free(nameptr, flavor='raw')
lltype.free(lenptr, flavor='raw')
@@ -428,7 +428,7 @@
strValue = rffi.cast(roci.Ptr(roci.OCIString), value)[0]
ptr = roci.OCIStringPtr(environment.handle, strValue)
size = roci.OCIStringSize(environment.handle, strValue)
- return config.w_string(space, ptr, size)
+ return config.w_string(space, ptr, rffi.cast(lltype.Signed, size))
elif typeCode == roci.OCI_TYPECODE_NUMBER:
return transform.OracleNumberToPythonFloat(
environment,
diff --git a/pypy/module/oracle/interp_pool.py b/pypy/module/oracle/interp_pool.py
--- a/pypy/module/oracle/interp_pool.py
+++ b/pypy/module/oracle/interp_pool.py
@@ -100,11 +100,13 @@
status, "SessionPool_New(): create pool")
self.w_name = config.w_string(space, poolnameptr[0],
- poolnamelenptr[0])
+ rffi.cast(lltype.Signed, poolnamelenptr[0]))
finally:
user_buf.clear()
password_buf.clear()
dsn_buf.clear()
+ lltype.free(poolnameptr, flavor='raw')
+ lltype.free(poolnamelenptr, flavor='raw')
return space.wrap(self)
@@ -128,10 +130,19 @@
self.checkConnected(space)
+ if __args__.keywords:
+ keywords = __args__.keywords + ["pool"]
+ else:
+ keywords = ["pool"]
+ if __args__.keywords_w:
+ keywords_w = __args__.keywords_w + [space.wrap(self)]
+ else:
+ keywords_w = [space.wrap(self)]
+
newargs = Arguments(space,
__args__.arguments_w,
- __args__.keywords + ["pool"],
- __args__.keywords_w + [space.wrap(self)])
+ keywords,
+ keywords_w)
return space.call_args(self.w_connectionType, newargs)
def release(self, space, w_connection):
diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py
--- a/pypy/module/oracle/interp_variable.py
+++ b/pypy/module/oracle/interp_variable.py
@@ -279,6 +279,7 @@
self.actualLength, self.returnCode,
allocatedElements, actualElementsPtr,
roci.OCI_DEFAULT)
+ nameBuffer.clear()
else:
status = roci.OCIBindByPos(
self.boundCursorHandle, bindHandlePtr,
@@ -601,6 +602,7 @@
def getValueProc(self, space, pos):
ptr = rffi.ptradd(self.data, pos * self.bufferSize)
length = rffi.cast(roci.Ptr(roci.ub4), ptr)[0]
+ length = rffi.cast(lltype.Signed, length)
ptr = rffi.ptradd(ptr, rffi.sizeof(roci.ub4))
return space.wrap(rffi.charpsize2str(ptr, length))
@@ -732,6 +734,7 @@
finally:
rffi.keep_buffer_alive_until_here(textbuf, text)
lltype.free(sizeptr, flavor='raw')
+ format_buf.clear()
if isinstance(self, VT_NumberAsString):
return w_strvalue
@@ -778,6 +781,8 @@
format_buf.ptr, format_buf.size,
None, 0,
dataptr)
+ text_buf.clear()
+ format_buf.clear()
self.environment.checkForError(
status, "NumberVar_SetValue(): from long")
return
@@ -810,6 +815,8 @@
format_buf.ptr, format_buf.size,
nls_params, len(nls_params),
dataptr)
+ text_buf.clear()
+ format_buf.clear()
self.environment.checkForError(
status, "NumberVar_SetValue(): from decimal")
return
diff --git a/pypy/module/oracle/roci.py b/pypy/module/oracle/roci.py
--- a/pypy/module/oracle/roci.py
+++ b/pypy/module/oracle/roci.py
@@ -73,7 +73,8 @@
defines = '''
OCI_ATTR_SERVER OCI_ATTR_SESSION OCI_ATTR_USERNAME OCI_ATTR_PASSWORD
OCI_ATTR_STMT_TYPE OCI_ATTR_PARAM OCI_ATTR_PARAM_COUNT OCI_ATTR_ROW_COUNT
- OCI_ATTR_NAME OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL
+ OCI_ATTR_NAME OCI_ATTR_INTERNAL_NAME OCI_ATTR_EXTERNAL_NAME
+ OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL
OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_REF_TDO
OCI_ATTR_SCHEMA_NAME OCI_ATTR_TYPE_NAME OCI_ATTR_TYPECODE
OCI_ATTR_NUM_TYPE_ATTRS OCI_ATTR_LIST_TYPE_ATTRS
diff --git a/pypy/module/oracle/test/test_connect.py b/pypy/module/oracle/test/test_connect.py
--- a/pypy/module/oracle/test/test_connect.py
+++ b/pypy/module/oracle/test/test_connect.py
@@ -41,6 +41,10 @@
if hasattr(self, 'cnx'):
self.cnx.close()
+ def test_constants(self):
+ assert '.' in oracle.version
+ assert oracle.paramstyle == 'named'
+
def test_connect(self):
self.cnx = oracle.connect(self.username, self.password,
self.tnsentry, threaded=True)
@@ -49,6 +53,13 @@
assert self.cnx.tnsentry == self.tnsentry
assert isinstance(self.cnx.version, str)
+ def test_connect_twophase(self):
+ self.cnx = oracle.connect(self.username, self.password,
+ self.tnsentry, twophase=True)
+ assert self.cnx.username == self.username
+ assert self.cnx.password == self.password
+ assert self.cnx.tnsentry == self.tnsentry
+
def test_singleArg(self):
self.cnx = oracle.connect("%s/%s@%s" % (self.username, self.password,
self.tnsentry))
diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py
--- a/pypy/module/pypyjit/__init__.py
+++ b/pypy/module/pypyjit/__init__.py
@@ -7,13 +7,15 @@
interpleveldefs = {
'set_param': 'interp_jit.set_param',
'residual_call': 'interp_jit.residual_call',
+ 'set_compile_hook': 'interp_jit.set_compile_hook',
}
def setup_after_space_initialization(self):
# force the __extend__ hacks to occur early
- import pypy.module.pypyjit.interp_jit
+ from pypy.module.pypyjit.interp_jit import pypyjitdriver
# add the 'defaults' attribute
from pypy.rlib.jit import PARAMETERS
space = self.space
+ pypyjitdriver.space = space
w_obj = space.wrap(PARAMETERS)
space.setattr(space.wrap(self), space.wrap('defaults'), w_obj)
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
@@ -12,6 +12,8 @@
from pypy.interpreter.pycode import PyCode, CO_GENERATOR
from pypy.interpreter.pyframe import PyFrame
from pypy.interpreter.pyopcode import ExitFrame
+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
@@ -49,13 +51,43 @@
greens = ['next_instr', 'is_being_profiled', 'pycode']
virtualizables = ['frame']
-## def compute_invariants(self, reds, next_instr, pycode):
-## # compute the information that really only depends on next_instr
-## # and pycode
-## frame = reds.frame
-## valuestackdepth = frame.valuestackdepth
-## blockstack = frame.blockstack
-## return (valuestackdepth, blockstack)
+ 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 space.is_true(cache.w_compile_hook):
+ memo = {}
+ list_w = [space.wrap(logger.repr_of_resop(memo, op))
+ for op in operations]
+ pycode = cast_base_ptr_to_instance(PyCode, ll_pycode)
+ try:
+ space.call_function(cache.w_compile_hook,
+ space.wrap('main'),
+ space.wrap(type),
+ space.newtuple([pycode,
+ space.wrap(next_instr),
+ space.wrap(is_being_profiled)]),
+ space.newlist(list_w))
+ except OperationError, e:
+ e.write_unraisable(space, "jit hook ", cache.w_compile_hook)
+
+ def on_compile_bridge(self, logger, orig_looptoken, operations, n):
+ space = self.space
+ cache = space.fromcache(Cache)
+ if space.is_true(cache.w_compile_hook):
+ memo = {}
+ list_w = [space.wrap(logger.repr_of_resop(memo, op))
+ for op in operations]
+ try:
+ space.call_function(cache.w_compile_hook,
+ space.wrap('main'),
+ space.wrap('bridge'),
+ space.wrap(n),
+ space.newlist(list_w))
+ except OperationError, e:
+ e.write_unraisable(space, "jit hook ", cache.w_compile_hook)
pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location,
get_jitcell_at = get_jitcell_at,
@@ -157,3 +189,28 @@
'''For testing. Invokes callable(...), but without letting
the JIT follow the call.'''
return space.call_args(w_callable, __args__)
+
+class Cache(object):
+ def __init__(self, space):
+ self.w_compile_hook = space.w_None
+
+ at unwrap_spec(ObjSpace, W_Root)
+def set_compile_hook(space, w_hook):
+ """ set_compile_hook(hook)
+
+ Set a compiling hook that will be called each time a loop is compiled.
+ The hook will be called with the following signature:
+ hook(merge_point_type, loop_type, greenkey or guard_number, operations)
+
+ for now merge point type is always `main`
+
+ loop_type can be either `loop` `entry_bridge` or `bridge`
+ in case loop is not `bridge`, greenkey will be a set of constants
+ for jit merge point. in case it's `main` it'll be a tuple
+ (code, offset, is_being_profiled)
+
+ XXX write down what else
+ """
+ cache = space.fromcache(Cache)
+ cache.w_compile_hook = w_hook
+ return space.w_None
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -14,7 +14,7 @@
modname, _ = modname.split('.', 1)
if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions',
'imp', 'sys', 'array', '_ffi', 'itertools', 'operator',
- 'posix', '_socket', '_sre', '_lsprof']:
+ 'posix', '_socket', '_sre', '_lsprof', '_weakref']:
return True
return False
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -0,0 +1,89 @@
+
+import py
+from pypy.conftest import gettestobjspace, option
+from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.gateway import interp2app
+from pypy.jit.metainterp.history import LoopToken
+from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.logger import Logger
+from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr,
+ cast_base_ptr_to_instance)
+from pypy.module.pypyjit.interp_jit import pypyjitdriver
+from pypy.jit.tool.oparser import parse
+from pypy.jit.metainterp.typesystem import llhelper
+
+class MockSD(object):
+ class cpu:
+ ts = llhelper
+
+class AppTestJitHook(object):
+ def setup_class(cls):
+ if option.runappdirect:
+ py.test.skip("Can't run this test with -A")
+ space = gettestobjspace(usemodules=('pypyjit',))
+ cls.space = space
+ w_f = space.appexec([], """():
+ def f():
+ pass
+ return f
+ """)
+ ll_code = cast_instance_to_base_ptr(w_f.code)
+ logger = Logger(MockSD())
+
+ oplist = parse("""
+ [i1, i2]
+ i3 = int_add(i1, i2)
+ guard_true(i3) []
+ """).operations
+
+ def interp_on_compile():
+ pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop',
+ 0, False, ll_code)
+
+ def interp_on_compile_bridge():
+ pypyjitdriver.on_compile_bridge(logger, LoopToken(), oplist, 0)
+
+ cls.w_on_compile = space.wrap(interp2app(interp_on_compile))
+ cls.w_on_compile_bridge = space.wrap(interp2app(interp_on_compile_bridge))
+
+ def test_on_compile(self):
+ import pypyjit
+ all = []
+
+ def hook(*args):
+ assert args[0] == 'main'
+ assert args[1] in ['loop', 'bridge']
+ all.append(args[2:])
+
+ self.on_compile()
+ pypyjit.set_compile_hook(hook)
+ assert not all
+ self.on_compile()
+ assert len(all) == 1
+ assert all[0][0][0].co_name == 'f'
+ assert all[0][0][1] == 0
+ assert all[0][0][2] == False
+ assert len(all[0][1]) == 2
+ assert 'int_add' in all[0][1][0]
+ self.on_compile_bridge()
+ assert len(all) == 2
+ pypyjit.set_compile_hook(None)
+ self.on_compile()
+ assert len(all) == 2
+
+ def test_on_compile_exception(self):
+ import pypyjit, sys, cStringIO
+
+ def hook(*args):
+ 1/0
+
+ pypyjit.set_compile_hook(hook)
+ s = cStringIO.StringIO()
+ prev = sys.stderr
+ sys.stderr = s
+ try:
+ self.on_compile()
+ finally:
+ sys.stderr = prev
+ assert 'jit hook' in s.getvalue()
+ assert 'ZeroDivisionError' in s.getvalue()
diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_model.py
@@ -20,7 +20,7 @@
def setup_method(self, meth):
self.filepath = self.tmpdir.join(meth.im_func.func_name + '.py')
- def run(self, func_or_src, args=[], **jitopts):
+ def run(self, func_or_src, args=[], import_site=False, **jitopts):
src = py.code.Source(func_or_src)
if isinstance(func_or_src, types.FunctionType):
funcname = func_or_src.func_name
@@ -39,7 +39,9 @@
# run a child pypy-c with logging enabled
logfile = self.filepath.new(ext='.log')
#
- cmdline = [sys.executable, '-S']
+ cmdline = [sys.executable]
+ if not import_site:
+ cmdline.append('-S')
for key, value in jitopts.iteritems():
cmdline += ['--jit', '%s=%s' % (key, value)]
cmdline.append(str(self.filepath))
@@ -465,7 +467,7 @@
j = ntohs(1) # ID: ntohs
a = 0
return i
- log = self.run(f)
+ log = self.run(f, import_site=True)
loop, = log.loops_by_id('ntohs')
assert loop.match_by_id('ntohs', """
guard_not_invalidated(descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
--- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
@@ -270,9 +270,8 @@
i17 = int_add_ovf(i8, 1)
guard_no_overflow(descr=<Guard5>)
i18 = force_token()
- i20 = int_sub(i17, 1)
--TICK--
- jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, descr=<Loop0>)
+ jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=<Loop0>)
""")
def test_default_and_kw(self):
@@ -481,10 +480,14 @@
assert log.result == (1000, 998)
loop, = log.loops_by_filename(self.filepath)
assert loop.match_by_id('append', """
- p14 = new_with_vtable(ConstClass(W_IntObject))
- setfield_gc(p14, i12, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
- call(ConstClass(ll_append__listPtr_objectPtr), p8, p14, descr=...)
+ 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>)
+ 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 .*>)
+ setarrayitem_gc(p17, i13, p19, descr=<GcPtrArrayDescr>)
""")
def test_range_iter(self):
@@ -1676,3 +1679,55 @@
loop, = log.loops_by_filename(self.filepath)
import pdb;pdb.set_trace()
assert loop.match_by_id('div', "") # optimized away
+
+ def test_oldstyle_newstyle_mix(self):
+ def main():
+ class A:
+ pass
+
+ class B(object, A):
+ def __init__(self, x):
+ self.x = x
+
+ i = 0
+ b = B(1)
+ while i < 100:
+ v = b.x # ID: loadattr
+ i += v
+ return i
+
+ log = self.run(main, [], threshold=80)
+ loop, = log.loops_by_filename(self.filepath)
+ loop.match_by_id('loadattr',
+ '''
+ guard_not_invalidated(descr=...)
+ i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...)
+ guard_no_exception(descr=...)
+ i21 = int_and(i19, _)
+ i22 = int_is_true(i21)
+ guard_true(i22, descr=...)
+ i26 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...)
+ guard_no_exception(descr=...)
+ i28 = int_and(i26, _)
+ i29 = int_is_true(i28)
+ guard_true(i29, descr=...)
+ ''')
+
+ def test_python_contains(self):
+ def main():
+ class A(object):
+ def __contains__(self, v):
+ return True
+
+ i = 0
+ a = A()
+ while i < 100:
+ i += i in a # ID: contains
+
+ log = self.run(main, [], threshold=80)
+ loop, = log.loops_by_filename(self.filemath)
+ # XXX: haven't confirmed his is correct, it's probably missing a
+ # few instructions
+ loop.match_by_id("contains", """
+ i1 = int_add(i0, 1)
+ """)
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -150,7 +150,7 @@
if operror is None:
return space.w_None
else:
- return space.wrap(operror.application_traceback)
+ return space.wrap(operror.get_traceback())
return None
def get_w_default_encoder(self):
diff --git a/pypy/module/sys/interp_encoding.py b/pypy/module/sys/interp_encoding.py
--- a/pypy/module/sys/interp_encoding.py
+++ b/pypy/module/sys/interp_encoding.py
@@ -43,16 +43,21 @@
#
encoding = base_encoding
if rlocale.HAVE_LANGINFO and rlocale.CODESET:
- oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None)
- rlocale.setlocale(rlocale.LC_CTYPE, "")
- loc_codeset = rlocale.nl_langinfo(rlocale.CODESET)
- if loc_codeset:
- codecmod = space.getbuiltinmodule('_codecs')
- w_res = space.call_function(space.getattr(codecmod,
- space.wrap('lookup')),
- space.wrap(loc_codeset))
- if space.is_true(w_res):
- encoding = loc_codeset
+ try:
+ oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None)
+ rlocale.setlocale(rlocale.LC_CTYPE, "")
+ try:
+ loc_codeset = rlocale.nl_langinfo(rlocale.CODESET)
+ if loc_codeset:
+ codecmod = space.getbuiltinmodule('_codecs')
+ w_res = space.call_method(codecmod, 'lookup',
+ space.wrap(loc_codeset))
+ if space.is_true(w_res):
+ encoding = loc_codeset
+ finally:
+ rlocale.setlocale(rlocale.LC_CTYPE, oldlocale)
+ except rlocale.LocaleError:
+ pass
return encoding
def getfilesystemencoding(space):
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -40,24 +40,24 @@
break
depth -= 1
f = ec.getnextframe_nohidden(f)
+ f.mark_as_escaped()
return space.wrap(f)
def setrecursionlimit(space, w_new_limit):
- """setrecursionlimit() is ignored (and not needed) on PyPy.
-
-On CPython it would set the maximum number of nested calls that can
-occur before a RuntimeError is raised. On PyPy overflowing the stack
-also causes RuntimeErrors, but the limit is checked at a lower level.
-(The limit is currenty hard-coded at 768 KB, corresponding to roughly
-1480 Python calls on Linux.)"""
+ """setrecursionlimit() sets the maximum number of nested calls that
+can occur before a RuntimeError is raised. On PyPy the limit is
+approximative and checked at a lower level. The default 1000
+reserves 768KB of stack space, which should suffice (on Linux,
+depending on the compiler settings) for ~1400 calls. Setting the
+value to N reserves N/1000 times 768KB of stack space.
+"""
+ from pypy.rlib.rstack import _stack_set_length_fraction
new_limit = space.int_w(w_new_limit)
if new_limit <= 0:
raise OperationError(space.w_ValueError,
space.wrap("recursion limit must be positive"))
- # for now, don't rewrite a warning but silently ignore the
- # recursion limit.
- #space.warn('setrecursionlimit() is ignored (and not needed) on PyPy', space.w_RuntimeWarning)
space.sys.recursionlimit = new_limit
+ _stack_set_length_fraction(new_limit * 0.001)
def getrecursionlimit(space):
"""Return the last value set by setrecursionlimit().
@@ -91,7 +91,7 @@
return space.newtuple([space.w_None,space.w_None,space.w_None])
else:
return space.newtuple([operror.w_type, operror.get_w_value(space),
- space.wrap(operror.application_traceback)])
+ space.wrap(operror.get_traceback())])
def exc_clear(space):
"""Clear global information on the current exception. Subsequent calls
diff --git a/pypy/module/test_lib_pypy/test_stackless.py b/pypy/module/test_lib_pypy/test_stackless.py
--- a/pypy/module/test_lib_pypy/test_stackless.py
+++ b/pypy/module/test_lib_pypy/test_stackless.py
@@ -8,15 +8,12 @@
space = gettestobjspace(usemodules=('_stackless', '_socket'))
cls.space = space
# cannot test the unpickle part on top of py.py
- cls.w_can_unpickle = space.wrap(bool(option.runappdirect))
def test_pickle(self):
import new, sys
mod = new.module('mod')
sys.modules['mod'] = mod
- mod.can_unpickle = self.can_unpickle
- mod.skip = skip
try:
exec '''
import pickle, sys
@@ -45,8 +42,6 @@
t = stackless.tasklet(demo)(lev)
stackless.run()
assert seen == range(1, lev+1) + range(lev, 0, -1)
-if not can_unpickle:
- skip("cannot test the unpickling part on top of py.py")
print "now running the clone"
tt = pickle.loads(blob)
tt.insert()
@@ -64,8 +59,6 @@
mod = new.module('mod')
sys.modules['mod'] = mod
- mod.can_unpickle = self.can_unpickle
- mod.skip = skip
try:
exec '''
import pickle, sys
diff --git a/pypy/module/test_lib_pypy/test_tputil.py b/pypy/module/test_lib_pypy/test_tputil.py
--- a/pypy/module/test_lib_pypy/test_tputil.py
+++ b/pypy/module/test_lib_pypy/test_tputil.py
@@ -28,9 +28,9 @@
from tputil import make_proxy
l = []
tp = make_proxy(l.append, type=list)
- x = len(tp)
+ x = tp[0:1]
assert len(l) == 1
- assert l[0].opname == '__len__'
+ assert l[0].opname == '__getslice__'
def test_simple(self):
from tputil import make_proxy
diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py
--- a/pypy/module/zipimport/test/test_zipimport.py
+++ b/pypy/module/zipimport/test/test_zipimport.py
@@ -1,7 +1,7 @@
from pypy.conftest import gettestobjspace
import marshal
-import py
+import py, os
import time
import struct
from pypy.module.imp.importing import get_pyc_magic, _w_long
@@ -15,6 +15,7 @@
cpy's regression tests
"""
compression = ZIP_STORED
+ pathsep = '/'
def make_pyc(cls, space, co, mtime):
data = marshal.dumps(co)
@@ -57,6 +58,7 @@
test_pyc = cls.make_pyc(space, co, now)
cls.w_test_pyc = space.wrap(test_pyc)
cls.w_compression = space.wrap(cls.compression)
+ cls.w_pathsep = space.wrap(cls.pathsep)
#ziptestmodule = tmpdir.ensure('ziptestmodule.zip').write(
ziptestmodule = tmpdir.join("somezip.zip")
cls.w_tmpzip = space.wrap(str(ziptestmodule))
@@ -100,6 +102,7 @@
from zipfile import ZipFile, ZipInfo
z = ZipFile(self.zipfile, 'w')
write_files = self.write_files
+ filename = filename.replace('/', self.pathsep)
write_files.append((filename, data))
for filename, data in write_files:
zinfo = ZipInfo(filename, time.localtime(self.now))
@@ -121,6 +124,7 @@
del _zip_directory_cache[self.zipfile]
def test_cache_subdir(self):
+ import os
self.writefile('x.py', '')
self.writefile('sub/__init__.py', '')
self.writefile('sub/yy.py', '')
@@ -130,7 +134,7 @@
assert main_importer is not sub_importer
assert main_importer.prefix == ""
- assert sub_importer.prefix == "sub/"
+ assert sub_importer.prefix == "sub" + os.path.sep
def test_good_bad_arguments(self):
from zipimport import zipimporter
@@ -262,7 +266,7 @@
import zipimport
data = "saddsadsa"
self.writefile("xxx", data)
- self.writefile("xx"+os.sep+"__init__.py", "5")
+ self.writefile("xx/__init__.py", "5")
self.writefile("yy.py", "3")
self.writefile('uu.pyc', self.test_pyc)
z = zipimport.zipimporter(self.zipfile)
@@ -287,8 +291,7 @@
"""
import os
import zipimport
- self.writefile(
- os.sep.join(("directory", "package", "__init__.py")), "")
+ self.writefile("directory/package/__init__.py", "")
importer = zipimport.zipimporter(self.zipfile + "/directory")
# Grab this so if the assertion fails, py.test will display its
# value. Not sure why it doesn't the assertion uses import.archive
@@ -296,15 +299,14 @@
archive = importer.archive
realprefix = importer.prefix
allbutlast = self.zipfile.split(os.path.sep)[:-1]
- prefix = 'directory/'
+ prefix = 'directory' + os.path.sep
assert archive == self.zipfile
assert realprefix == prefix
def test_subdirectory_importer(self):
import os
import zipimport
- self.writefile(
- os.sep.join(("directory", "package", "__init__.py")), "")
+ self.writefile("directory/package/__init__.py", "")
z = zipimport.zipimporter(self.zipfile + "/directory")
mod = z.load_module("package")
assert z.is_package("package")
@@ -313,14 +315,9 @@
def test_subdirectory_twice(self):
import os, zipimport
- self.writefile(
- os.sep.join(("package", "__init__.py")), "")
- self.writefile(
- os.sep.join(("package", "subpackage",
- "__init__.py")), "")
- self.writefile(
- os.sep.join(("package", "subpackage",
- "foo.py")), "")
+ self.writefile("package/__init__.py", "")
+ self.writefile("package/subpackage/__init__.py", "")
+ self.writefile("package/subpackage/foo.py", "")
import sys
print sys.path
mod = __import__('package.subpackage.foo', None, None, [])
@@ -331,8 +328,7 @@
"""
import os
import zipimport
- self.writefile(
- os.sep.join(("directory", "package", "__init__.py")), "")
+ self.writefile("directory/package/__init__.py", "")
importer = zipimport.zipimporter(self.zipfile + "/directory")
l = [i for i in zipimport._zip_directory_cache]
assert len(l)
@@ -370,3 +366,8 @@
except ImportError:
py.test.skip("zlib not available, cannot test compressed zipfiles")
cls.make_class()
+
+
+if os.sep != '/':
+ class AppTestNativePathSep(AppTestZipimport):
+ pathsep = os.sep
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -207,34 +207,51 @@
return space.get_and_call_function(w_descr, w_obj, w_name)
def is_true(space, w_obj):
- w_descr = space.lookup(w_obj, '__nonzero__')
+ method = "__nonzero__"
+ w_descr = space.lookup(w_obj, method)
if w_descr is None:
- w_descr = space.lookup(w_obj, '__len__')
+ method = "__len__"
+ w_descr = space.lookup(w_obj, method)
if w_descr is None:
return True
w_res = space.get_and_call_function(w_descr, w_obj)
# more shortcuts for common cases
- if w_res is space.w_False:
+ if space.is_w(w_res, space.w_False):
return False
- if w_res is space.w_True:
+ if space.is_w(w_res, space.w_True):
return True
w_restype = space.type(w_res)
- if (space.is_w(w_restype, space.w_bool) or
- space.is_w(w_restype, space.w_int)):
+ # Note there is no check for bool here because the only possible
+ # instances of bool are w_False and w_True, which are checked above.
+ if (space.is_w(w_restype, space.w_int) or
+ space.is_w(w_restype, space.w_long)):
return space.int_w(w_res) != 0
else:
- raise OperationError(space.w_TypeError,
- space.wrap('__nonzero__ should return '
- 'bool or int'))
+ msg = "%s should return bool or integer" % (method,)
+ raise OperationError(space.w_TypeError, space.wrap(msg))
- def nonzero(self, w_obj):
- if self.is_true(w_obj):
- return self.w_True
+ def nonzero(space, w_obj):
+ if space.is_true(w_obj):
+ return space.w_True
else:
- return self.w_False
+ return space.w_False
-## def len(self, w_obj):
-## XXX needs to check that the result is an int (or long?) >= 0
+ def len(space, w_obj):
+ w_descr = space.lookup(w_obj, '__len__')
+ if w_descr is None:
+ name = space.type(w_obj).getname(space)
+ msg = "'%s' has no length" % (name,)
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ w_res = space.get_and_call_function(w_descr, w_obj)
+ space._check_len_result(w_res)
+ return w_res
+
+ def _check_len_result(space, w_obj):
+ # Will complain if result is too big.
+ result = space.int_w(w_obj)
+ if result < 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("__len__() should return >= 0"))
def iter(space, w_obj):
w_descr = space.lookup(w_obj, '__iter__')
@@ -376,6 +393,9 @@
w_descr = space.lookup(w_container, '__contains__')
if w_descr is not None:
return space.get_and_call_function(w_descr, w_container, w_item)
+ return space._contains(w_container, w_item)
+
+ def _contains(space, w_container, w_item):
w_iter = space.iter(w_container)
while 1:
try:
diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py
--- a/pypy/objspace/std/callmethod.py
+++ b/pypy/objspace/std/callmethod.py
@@ -12,7 +12,7 @@
from pypy.interpreter import function
from pypy.objspace.descroperation import object_getattribute
-from pypy.rlib import jit, rstack # for resume points
+from pypy.rlib import jit
from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \
LOOKUP_METHOD_mapdict_fill_cache_method
@@ -51,6 +51,7 @@
# this handles directly the common case
# module.function(args..)
w_value = w_obj.getdictvalue(space, name)
+ # xxx we could also use the mapdict cache in that case, probably
else:
typ = type(w_descr)
if typ is function.Function or typ is function.FunctionWithFixedCode:
@@ -64,7 +65,7 @@
not jit.we_are_jitted()):
# let mapdict cache stuff
LOOKUP_METHOD_mapdict_fill_cache_method(
- f.getcode(), nameindex, w_obj, w_type, w_descr)
+ space, f.getcode(), name, nameindex, w_obj, w_type)
return
if w_value is None:
w_value = space.getattr(w_obj, w_name)
@@ -83,7 +84,6 @@
w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
try:
w_result = f.space.call_valuestack(w_callable, n, f)
- rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result)
finally:
f.dropvalues(n_args + 2)
else:
@@ -108,7 +108,6 @@
w_result = f.space.call_args_and_c_profile(f, w_callable, args)
else:
w_result = f.space.call_args(w_callable, args)
- rstack.resume_point("CALL_METHOD_KW", f, returns=w_result)
f.pushvalue(w_result)
diff --git a/pypy/objspace/std/floattype.py b/pypy/objspace/std/floattype.py
--- a/pypy/objspace/std/floattype.py
+++ b/pypy/objspace/std/floattype.py
@@ -14,10 +14,8 @@
float_as_integer_ratio = SMM("as_integer_ratio", 1)
float_hex = SMM("hex", 1)
-float_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any float.")
-
-def float_conjugate__ANY(space, w_float):
- return space.pos(w_float)
+def descr_conjugate(space, w_float):
+ return space.float(w_float)
register_all(vars(), globals())
@@ -168,10 +166,10 @@
if total_digits > min(const_one, const_two) // 4:
raise OperationError(space.w_ValueError, space.wrap("way too long"))
if i < length and (s[i] == "p" or s[i] == "P"):
+ i += 1
if i == length:
raise OperationError(space.w_ValueError,
space.wrap("invalid hex string"))
- i += 1
exp_sign = 1
if s[i] == "-" or s[i] == "+":
if s[i] == "-":
@@ -264,7 +262,7 @@
return space.call_function(w_cls, w_float)
def descr_get_real(space, w_obj):
- return w_obj
+ return space.float(w_obj)
def descr_get_imag(space, w_obj):
return space.wrap(0.0)
@@ -280,6 +278,7 @@
as_classmethod=True),
fromhex = gateway.interp2app(descr_fromhex,
as_classmethod=True),
+ conjugate = gateway.interp2app(descr_conjugate),
real = typedef.GetSetProperty(descr_get_real),
imag = typedef.GetSetProperty(descr_get_imag),
)
diff --git a/pypy/objspace/std/inttype.py b/pypy/objspace/std/inttype.py
--- a/pypy/objspace/std/inttype.py
+++ b/pypy/objspace/std/inttype.py
@@ -11,14 +11,19 @@
# ____________________________________________________________
-int_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any int.")
+def descr_conjugate(space, w_int):
+ "Returns self, the complex conjugate of any int."
+ return space.int(w_int)
-def int_conjugate__ANY(space, w_int):
- return space.pos(w_int)
+def descr_bit_length(space, w_int):
+ """int.bit_length() -> int
-int_bit_length = SMM("bit_length", 1, doc="int.bit_length() -> int\n\nNumber of bits necessary to represent self in binary.\n>>> bin(37)\n'0b100101'\n>>> (37).bit_length()\n6")
-
-def int_bit_length__ANY(space, w_int):
+ Number of bits necessary to represent self in binary.
+ >>> bin(37)
+ '0b100101'
+ >>> (37).bit_length()
+ 6
+ """
val = space.int_w(w_int)
if val < 0:
val = -val
@@ -28,8 +33,6 @@
val >>= 1
return space.wrap(bits)
-register_all(vars(), globals())
-
def wrapint(space, x):
if space.config.objspace.std.withsmallint:
@@ -179,7 +182,7 @@
return space.wrap(1)
def descr_get_real(space, w_obj):
- return w_obj
+ return space.int(w_obj)
def descr_get_imag(space, w_obj):
return space.wrap(0)
@@ -196,6 +199,8 @@
non-string. If the argument is outside the integer range a long object
will be returned instead.''',
__new__ = gateway.interp2app(descr__new__),
+ conjugate = gateway.interp2app(descr_conjugate),
+ bit_length = gateway.interp2app(descr_bit_length),
numerator = typedef.GetSetProperty(descr_get_numerator),
denominator = typedef.GetSetProperty(descr_get_denominator),
real = typedef.GetSetProperty(descr_get_real),
diff --git a/pypy/objspace/std/longtype.py b/pypy/objspace/std/longtype.py
--- a/pypy/objspace/std/longtype.py
+++ b/pypy/objspace/std/longtype.py
@@ -4,12 +4,8 @@
from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
from pypy.objspace.std.strutil import string_to_bigint, ParseStringError
-long_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any long.")
-
-def long_conjugate__ANY(space, w_int):
- return space.pos(w_int)
-
-register_all(vars(), globals())
+def descr_conjugate(space, w_int):
+ return space.long(w_int)
def descr__new__(space, w_longtype, w_x=0, w_base=gateway.NoneNotWrapped):
@@ -104,7 +100,7 @@
return space.newlong(1)
def descr_get_real(space, w_obj):
- return w_obj
+ return space.long(w_obj)
def descr_get_imag(space, w_obj):
return space.newlong(0)
@@ -128,6 +124,7 @@
string, use the optional base. It is an error to supply a base when
converting a non-string.''',
__new__ = gateway.interp2app(descr__new__),
+ conjugate = gateway.interp2app(descr_conjugate),
numerator = typedef.GetSetProperty(descr_get_numerator),
denominator = typedef.GetSetProperty(descr_get_denominator),
real = typedef.GetSetProperty(descr_get_real),
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -8,6 +8,7 @@
from pypy.objspace.std.dictmultiobject import IteratorImplementation
from pypy.objspace.std.dictmultiobject import _is_sane_hash
from pypy.objspace.std.objectobject import W_ObjectObject
+from pypy.objspace.std.typeobject import TypeCell
# ____________________________________________________________
# attribute shapes
@@ -753,22 +754,40 @@
w_descr = w_type.getattribute_if_not_from_object()
if w_descr is not None:
return space._handle_getattribute(w_descr, w_obj, w_name)
-
version_tag = w_type.version_tag()
if version_tag is not None:
name = space.str_w(w_name)
- w_descr = w_type.lookup(name)
+ # We need to care for obscure cases in which the w_descr is
+ # a TypeCell, which may change without changing the version_tag
+ assert space.config.objspace.std.withmethodcache
+ _, w_descr = w_type._pure_lookup_where_with_method_cache(
+ name, version_tag)
+ #
selector = ("", INVALID)
- if w_descr is not None and space.is_data_descr(w_descr):
+ if w_descr is None:
+ selector = (name, DICT) #common case: no such attr in the class
+ elif isinstance(w_descr, TypeCell):
+ pass # we have a TypeCell in the class: give up
+ elif space.is_data_descr(w_descr):
+ # we have a data descriptor, which means the dictionary value
+ # (if any) has no relevance.
from pypy.interpreter.typedef import Member
descr = space.interpclass_w(w_descr)
- if isinstance(descr, Member):
+ if isinstance(descr, Member): # it is a slot -- easy case
selector = ("slot", SLOTS_STARTING_FROM + descr.index)
else:
+ # There is a non-data descriptor in the class. If there is
+ # also a dict attribute, use the latter, caching its position.
+ # If not, we loose. We could do better in this case too,
+ # but we don't care too much; the common case of a method
+ # invocation is handled by LOOKUP_METHOD_xxx below.
selector = (name, DICT)
+ #
if selector[1] != INVALID:
index = map.index(selector)
if index >= 0:
+ # Note that if map.terminator is a DevolvedDictTerminator,
+ # map.index() will always return -1 if selector[1]==DICT.
_fill_cache(pycode, nameindex, map, version_tag, index)
return w_obj._mapdict_read_storage(index)
if space.config.objspace.std.withmethodcachecounter:
@@ -788,11 +807,26 @@
return True
return False
-def LOOKUP_METHOD_mapdict_fill_cache_method(pycode, nameindex, w_obj, w_type, w_method):
+def LOOKUP_METHOD_mapdict_fill_cache_method(space, pycode, name, nameindex,
+ w_obj, w_type):
version_tag = w_type.version_tag()
if version_tag is None:
return
map = w_obj._get_mapdict_map()
- if map is None:
+ if map is None or isinstance(map.terminator, DevolvedDictTerminator):
+ return
+ # We know here that w_obj.getdictvalue(space, name) just returned None,
+ # so the 'name' is not in the instance. We repeat the lookup to find it
+ # in the class, this time taking care of the result: it can be either a
+ # quasi-constant class attribute, or actually a TypeCell --- which we
+ # must not cache. (It should not be None here, but you never know...)
+ assert space.config.objspace.std.withmethodcache
+ _, w_method = w_type._pure_lookup_where_with_method_cache(name,
+ version_tag)
+ if w_method is None or isinstance(w_method, TypeCell):
return
_fill_cache(pycode, nameindex, map, version_tag, -1, w_method)
+
+# XXX fix me: if a function contains a loop with both LOAD_ATTR and
+# XXX LOOKUP_METHOD on the same attribute name, it keeps trashing and
+# XXX rebuilding the cache
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -15,6 +15,7 @@
_registered_implementations.add(implcls)
option_to_typename = {
+ "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"],
"withsmallint" : ["smallintobject.W_SmallIntObject"],
"withsmalllong" : ["smalllongobject.W_SmallLongObject"],
"withstrslice" : ["strsliceobject.W_StringSliceObject"],
@@ -71,6 +72,7 @@
from pypy.objspace.std import smallintobject
from pypy.objspace.std import smalllongobject
from pypy.objspace.std import tupleobject
+ from pypy.objspace.std import smalltupleobject
from pypy.objspace.std import listobject
from pypy.objspace.std import dictmultiobject
from pypy.objspace.std import stringobject
@@ -253,6 +255,9 @@
(listobject.W_ListObject,
rangeobject.delegate_range2list),
]
+ if config.objspace.std.withsmalltuple:
+ self.typeorder[smalltupleobject.W_SmallTupleObject] += [
+ (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)]
# put W_Root everywhere
self.typeorder[W_Root] = []
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -266,6 +266,7 @@
return None
def unwrap(self, w_obj):
+ """NOT_RPYTHON"""
if isinstance(w_obj, Wrappable):
return w_obj
if isinstance(w_obj, model.W_Object):
@@ -295,9 +296,10 @@
return newlong(self, val)
def newtuple(self, list_w):
+ from pypy.objspace.std.tupletype import wraptuple
assert isinstance(list_w, list)
make_sure_not_resized(list_w)
- return W_TupleObject(list_w)
+ return wraptuple(self, list_w)
def newlist(self, list_w):
return W_ListObject(list_w)
diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/smalltupleobject.py
@@ -0,0 +1,157 @@
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.model import registerimplementation, W_Object
+from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.inttype import wrapint
+from pypy.objspace.std.multimethod import FailedToImplement
+from pypy.rlib.rarithmetic import intmask
+from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
+from pypy.objspace.std import slicetype
+from pypy.interpreter import gateway
+from pypy.rlib.debug import make_sure_not_resized
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.objspace.std.tupleobject import W_TupleObject
+
+class W_SmallTupleObject(W_Object):
+ from pypy.objspace.std.tupletype import tuple_typedef as typedef
+
+ def tolist(self):
+ raise NotImplementedError
+
+ def length(self):
+ raise NotImplementedError
+
+ def getitem(self, index):
+ raise NotImplementedError
+
+ def hash(self, space):
+ raise NotImplementedError
+
+ def eq(self, space, w_other):
+ raise NotImplementedError
+
+ def setitem(self, index, w_item):
+ raise NotImplementedError
+
+ def unwrap(w_tuple, space):
+ items = [space.unwrap(w_item) for w_item in w_tuple.tolist()]
+ return tuple(items)
+
+def make_specialized_class(n):
+ iter_n = unrolling_iterable(range(n))
+ class cls(W_SmallTupleObject):
+
+ def __init__(self, values):
+ assert len(values) == n
+ for i in iter_n:
+ setattr(self, 'w_value%s' % i, values[i])
+
+ def tolist(self):
+ l = [None] * n
+ for i in iter_n:
+ l[i] = getattr(self, 'w_value%s' % i)
+ return l
+
+ def length(self):
+ return n
+
+ def getitem(self, index):
+ for i in iter_n:
+ if index == i:
+ return getattr(self,'w_value%s' % i)
+ raise IndexError
+
+ def setitem(self, index, w_item):
+ for i in iter_n:
+ if index == i:
+ setattr(self, 'w_value%s' % i, w_item)
+ return
+ raise IndexError
+
+ def eq(self, space, w_other):
+ if self.length() != w_other.length():
+ return space.w_False
+ for i in iter_n:
+ item1 = self.getitem(i)
+ item2 = w_other.getitem(i)
+ if not space.eq_w(item1, item2):
+ return space.w_False
+ return space.w_True
+
+ def hash(self, space):
+ mult = 1000003
+ x = 0x345678
+ z = self.length()
+ for i in iter_n:
+ w_item = self.getitem(i)
+ y = space.int_w(space.hash(w_item))
+ x = (x ^ y) * mult
+ z -= 1
+ mult += 82520 + z + z
+ x += 97531
+ return space.wrap(intmask(x))
+
+ cls.__name__ = "W_SmallTupleObject%s" % n
+ return cls
+
+W_SmallTupleObject2 = make_specialized_class(2)
+W_SmallTupleObject3 = make_specialized_class(3)
+W_SmallTupleObject4 = make_specialized_class(4)
+W_SmallTupleObject5 = make_specialized_class(5)
+W_SmallTupleObject6 = make_specialized_class(6)
+W_SmallTupleObject7 = make_specialized_class(7)
+W_SmallTupleObject8 = make_specialized_class(8)
+
+registerimplementation(W_SmallTupleObject)
+
+def delegate_SmallTuple2Tuple(space, w_small):
+ return W_TupleObject(w_small.tolist())
+
+def len__SmallTuple(space, w_tuple):
+ return space.wrap(w_tuple.length())
+
+def getitem__SmallTuple_ANY(space, w_tuple, w_index):
+ index = space.getindex_w(w_index, space.w_IndexError, "tuple index")
+ if index < 0:
+ index += w_tuple.length()
+ try:
+ return w_tuple.getitem(index)
+ except IndexError:
+ raise OperationError(space.w_IndexError,
+ space.wrap("tuple index out of range"))
+
+def getitem__SmallTuple_Slice(space, w_tuple, w_slice):
+ length = w_tuple.length()
+ start, stop, step, slicelength = w_slice.indices4(space, length)
+ assert slicelength >= 0
+ subitems = [None] * slicelength
+ for i in range(slicelength):
+ subitems[i] = w_tuple.getitem(start)
+ start += step
+ return space.newtuple(subitems)
+
+def mul_smalltuple_times(space, w_tuple, w_times):
+ try:
+ times = space.getindex_w(w_times, space.w_OverflowError)
+ except OperationError, e:
+ if e.match(space, space.w_TypeError):
+ raise FailedToImplement
+ raise
+ if times == 1 and space.type(w_tuple) == space.w_tuple:
+ return w_tuple
+ items = w_tuple.tolist()
+ return space.newtuple(items * times)
+
+def mul__SmallTuple_ANY(space, w_tuple, w_times):
+ return mul_smalltuple_times(space, w_tuple, w_times)
+
+def mul__ANY_SmallTuple(space, w_times, w_tuple):
+ return mul_smalltuple_times(space, w_tuple, w_times)
+
+def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2):
+ return w_tuple1.eq(space, w_tuple2)
+
+def hash__SmallTuple(space, w_tuple):
+ return w_tuple.hash(space)
+
+from pypy.objspace.std import tupletype
+register_all(vars(), tupletype)
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -252,15 +252,30 @@
res_w = []
start = 0
- while maxsplit != 0:
- next = value.find(by, start)
- if next < 0:
- break
- res_w.append(sliced(space, value, start, next, w_self))
- start = next + bylen
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
+ if bylen == 1 and maxsplit < 0:
+ # fast path: uses str.rfind(character) and str.count(character)
+ by = by[0] # annotator hack: string -> char
+ count = value.count(by)
+ res_w = [None] * (count + 1)
+ end = len(value)
+ while count >= 0:
+ assert end >= 0
+ prev = value.rfind(by, 0, end)
+ start = prev + 1
+ assert start >= 0
+ res_w[count] = sliced(space, value, start, end, w_self)
+ count -= 1
+ end = prev
+ else:
+ while maxsplit != 0:
+ next = value.find(by, start)
+ if next < 0:
+ break
+ res_w.append(sliced(space, value, start, next, w_self))
+ start = next + bylen
+ maxsplit -= 1 # NB. if it's already < 0, it stays < 0
+ res_w.append(sliced(space, value, start, len(value), w_self))
- res_w.append(sliced(space, value, start, len(value), w_self))
return space.newlist(res_w)
def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -63,6 +63,19 @@
def setup_class(cls):
cls.w_py26 = cls.space.wrap(sys.version_info >= (2, 6))
+ def test_conjugate(self):
+ assert (1.).conjugate() == 1.
+ assert (-1.).conjugate() == -1.
+
+ class F(float):
+ pass
+ assert F(1.).conjugate() == 1.
+
+ class F(float):
+ def __pos__(self):
+ return 42.
+ assert F(1.).conjugate() == 1.
+
def test_negatives(self):
assert -1.1 < 0
assert -0.1 < 0
@@ -417,6 +430,11 @@
f = 1.1234e200
assert f.__format__("G") == "1.1234E+200"
+ def test_float_real(self):
+ class A(float): pass
+ b = A(5).real
+ assert type(b) is float
+
class AppTestFloatHex:
def w_identical(self, x, y):
@@ -746,3 +764,6 @@
pass
else:
self.identical(x, float.fromhex(x.hex()))
+
+ def test_invalid(self):
+ raises(ValueError, float.fromhex, "0P")
diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -285,6 +285,19 @@
class AppTestInt:
+ def test_conjugate(self):
+ assert (1).conjugate() == 1
+ assert (-1).conjugate() == -1
+
+ class I(int):
+ pass
+ assert I(1).conjugate() == 1
+
+ class I(int):
+ def __pos__(self):
+ return 42
+ assert I(1).conjugate() == 1
+
def test_trunc(self):
import math
assert math.trunc(1) == 1
@@ -480,6 +493,11 @@
]:
assert val.bit_length() == bits
+ def test_int_real(self):
+ class A(int): pass
+ b = A(5).real
+ assert type(b) is int
+
class AppTestIntOptimizedAdd(AppTestInt):
def setup_class(cls):
diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -300,6 +300,11 @@
assert type(L(7).conjugate()) is long
+ class L(long):
+ def __pos__(self):
+ return 43
+ assert L(7).conjugate() == 7L
+
def test_bit_length(self):
assert 8L.bit_length() == 4
assert (-1<<40).bit_length() == 41
@@ -323,3 +328,7 @@
assert type(as_long) is long
assert as_long == 64
+ def test_long_real(self):
+ class A(long): pass
+ b = A(5).real
+ assert type(b) is long
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -902,7 +902,53 @@
return c.m()
val = f()
assert val == 42
- f()
+ f()
+
+ def test_bug_lookup_method_devolved_dict_caching(self):
+ class A(object):
+ def method(self):
+ return 42
+ a = A()
+ a.__dict__[1] = 'foo'
+ got = a.method()
+ assert got == 42
+ a.__dict__['method'] = lambda: 43
+ got = a.method()
+ assert got == 43
+
+ def test_bug_method_change(self):
+ class A(object):
+ def method(self):
+ return 42
+ a = A()
+ got = a.method()
+ assert got == 42
+ A.method = lambda self: 43
+ got = a.method()
+ assert got == 43
+ A.method = lambda self: 44
+ got = a.method()
+ assert got == 44
+
+ def test_bug_slot_via_changing_member_descr(self):
+ class A(object):
+ __slots__ = ['a', 'b', 'c', 'd']
+ x = A()
+ x.a = 'a'
+ x.b = 'b'
+ x.c = 'c'
+ x.d = 'd'
+ got = x.a
+ assert got == 'a'
+ A.a = A.b
+ got = x.a
+ assert got == 'b'
+ A.a = A.c
+ got = x.a
+ assert got == 'c'
+ A.a = A.d
+ got = x.a
+ assert got == 'd'
class AppTestGlobalCaching(AppTestWithMapDict):
def setup_class(cls):
diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_smalltupleobject.py
@@ -0,0 +1,86 @@
+from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject
+from pypy.conftest import gettestobjspace
+
+class AppTestW_SmallTupleObject(AppTestW_TupleObject):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+ cls.w_issmall = cls.space.appexec([], """():
+ import __pypy__
+ def issmall(obj):
+ assert "SmallTuple" in __pypy__.internal_repr(obj)
+ return issmall
+ """)
+
+ def test_smalltuple(self):
+ self.issmall((1,2))
+ self.issmall((1,2,3))
+
+ def test_slicing_to_small(self):
+ self.issmall((1, 2, 3)[0:2]) # SmallTuple2
+ self.issmall((1, 2, 3)[0:2:1])
+
+ self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3
+ self.issmall((1, 2, 3, 4)[0:3:1])
+
+ def test_adding_to_small(self):
+ self.issmall((1,)+(2,)) # SmallTuple2
+ self.issmall((1,1)+(2,)) # SmallTuple3
+ self.issmall((1,)+(2,3))
+
+ def test_multiply_to_small(self):
+ self.issmall((1,)*2)
+ self.issmall((1,)*3)
+
+ def test_slicing_from_small(self):
+ assert (1,2)[0:1:1] == (1,)
+ assert (1,2,3)[0:2:1] == (1,2)
+
+ def test_eq(self):
+ a = (1,2,3)
+ b = (1,2,3)
+ assert a == b
+
+ c = (1,3,2)
+ assert a != c
+
+ def test_hash(self):
+ a = (1,2,3)
+ b = (1,2,3)
+ assert hash(a) == hash(b)
+
+ c = (1,3,2)
+ assert hash(a) != hash(c)
+
+class TestW_SmallTupleObject():
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+
+ def test_issmalltupleobject(self):
+ w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+ assert isinstance(w_tuple, W_SmallTupleObject)
+
+ def test_hash_agains_normal_tuple(self):
+ normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False})
+ w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)])
+
+ smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+ w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)])
+
+ assert isinstance(w_smalltuple, W_SmallTupleObject)
+ assert isinstance(w_tuple, W_TupleObject)
+ assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple))
+ assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple))
+ assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple)))
+
+ def test_setitem(self):
+ w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+ w_smalltuple.setitem(0, self.space.wrap(5))
+ list_w = w_smalltuple.tolist()
+ assert len(list_w) == 2
+ assert self.space.eq_w(list_w[0], self.space.wrap(5))
+ assert self.space.eq_w(list_w[1], self.space.wrap(2))
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -23,7 +23,7 @@
return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist))
def unwrap(w_tuple, space):
- items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] # XXX generic mixed types unwrap
+ items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems]
return tuple(items)
registerimplementation(W_TupleObject)
@@ -56,12 +56,12 @@
for i in range(slicelength):
subitems[i] = items[start]
start += step
- return W_TupleObject(subitems)
+ return space.newtuple(subitems)
def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop):
length = len(w_tuple.wrappeditems)
start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- return W_TupleObject(w_tuple.wrappeditems[start:stop])
+ return space.newtuple(w_tuple.wrappeditems[start:stop])
def contains__Tuple_ANY(space, w_tuple, w_obj):
for w_item in w_tuple.wrappeditems:
@@ -76,7 +76,7 @@
def add__Tuple_Tuple(space, w_tuple1, w_tuple2):
items1 = w_tuple1.wrappeditems
items2 = w_tuple2.wrappeditems
- return W_TupleObject(items1 + items2)
+ return space.newtuple(items1 + items2)
def mul_tuple_times(space, w_tuple, w_times):
try:
@@ -88,7 +88,7 @@
if times == 1 and space.type(w_tuple) == space.w_tuple:
return w_tuple
items = w_tuple.wrappeditems
- return W_TupleObject(items * times)
+ return space.newtuple(items * times)
def mul__Tuple_ANY(space, w_tuple, w_times):
return mul_tuple_times(space, w_tuple, w_times)
@@ -162,7 +162,7 @@
return intmask(x)
def getnewargs__Tuple(space, w_tuple):
- return space.newtuple([W_TupleObject(w_tuple.wrappeditems)])
+ return space.newtuple([space.newtuple(w_tuple.wrappeditems)])
def tuple_count__Tuple_ANY(space, w_tuple, w_obj):
count = 0
diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py
--- a/pypy/objspace/std/tupletype.py
+++ b/pypy/objspace/std/tupletype.py
@@ -3,6 +3,31 @@
from pypy.objspace.std.register_all import register_all
from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
+def wraptuple(space, list_w):
+ from pypy.objspace.std.tupleobject import W_TupleObject
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8
+ if space.config.objspace.std.withsmalltuple:
+ if len(list_w) == 2:
+ return W_SmallTupleObject2(list_w)
+ if len(list_w) == 3:
+ return W_SmallTupleObject3(list_w)
+ if len(list_w) == 4:
+ return W_SmallTupleObject4(list_w)
+ if len(list_w) == 5:
+ return W_SmallTupleObject5(list_w)
+ if len(list_w) == 6:
+ return W_SmallTupleObject6(list_w)
+ if len(list_w) == 7:
+ return W_SmallTupleObject7(list_w)
+ if len(list_w) == 8:
+ return W_SmallTupleObject8(list_w)
+ return W_TupleObject(list_w)
tuple_count = SMM("count", 2,
doc="count(obj) -> number of times obj appears in the tuple")
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -524,6 +524,31 @@
assert issubclass(B, B)
assert issubclass(23, B)
+ def test_truth_of_long(self):
+ class X(object):
+ def __len__(self): return 1L
+ __nonzero__ = __len__
+ assert X()
+ del X.__nonzero__
+ assert X()
+
+ def test_len_overflow(self):
+ import sys
+ class X(object):
+ def __len__(self):
+ return sys.maxsize + 1
+ raises(OverflowError, len, X())
+
+ def test_len_underflow(self):
+ import sys
+ class X(object):
+ def __len__(self):
+ return -1
+ raises(ValueError, len, X())
+ class Y(object):
+ def __len__(self):
+ return -1L
+ raises(ValueError, len, Y())
class AppTestWithBuiltinShortcut(AppTest_Descroperation):
OPTIONS = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/objspace/trace.py b/pypy/objspace/trace.py
--- a/pypy/objspace/trace.py
+++ b/pypy/objspace/trace.py
@@ -110,10 +110,10 @@
self.result.append(EnterFrame(frame))
self.ec.enter(frame)
- def leave(self, frame, w_exitvalue):
+ def leave(self, frame, w_exitvalue, got_exception):
""" called just after evaluating of a frame is suspended/finished. """
self.result.append(LeaveFrame(frame))
- self.ec.leave(frame, w_exitvalue)
+ self.ec.leave(frame, w_exitvalue, got_exception)
def bytecode_trace(self, frame):
""" called just before execution of a bytecode. """
diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py
--- a/pypy/rlib/_jit_vref.py
+++ b/pypy/rlib/_jit_vref.py
@@ -50,6 +50,7 @@
def rtype_simple_call(self, hop):
[v] = hop.inputargs(self)
+ hop.exception_is_here()
v = hop.genop('jit_force_virtual', [v], resulttype = OBJECTPTR)
return hop.genop('cast_pointer', [v], resulttype = hop.r_result)
@@ -65,6 +66,7 @@
lowleveltype = OBJECT
def rtype_simple_call(self, hop):
[v] = hop.inputargs(self)
+ hop.exception_is_here()
v = hop.genop('jit_force_virtual', [v], resulttype = OBJECT)
return hop.genop('oodowncast', [v], resulttype = hop.r_result)
diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py
--- a/pypy/rlib/debug.py
+++ b/pypy/rlib/debug.py
@@ -140,6 +140,40 @@
return hop.inputconst(lltype.Bool, False)
+def debug_offset():
+ """ Return an offset in log file
+ """
+ return -1
+
+class Entry(ExtRegistryEntry):
+ _about_ = debug_offset
+
+ def compute_result_annotation(self):
+ from pypy.annotation import model as annmodel
+ return annmodel.SomeInteger()
+
+ def specialize_call(self, hop):
+ from pypy.rpython.lltypesystem import lltype
+ hop.exception_cannot_occur()
+ return hop.genop('debug_offset', [], resulttype=lltype.Signed)
+
+
+def debug_flush():
+ """ Flushes the debug file
+ """
+ pass
+
+class Entry(ExtRegistryEntry):
+ _about_ = debug_flush
+
+ def compute_result_annotation(self):
+ return None
+
+ def specialize_call(self, hop):
+ hop.exception_cannot_occur()
+ return hop.genop('debug_flush', [])
+
+
def llinterpcall(RESTYPE, pythonfunction, *args):
"""When running on the llinterp, this causes the llinterp to call to
the provided Python function with the run-time value of the given args.
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -113,7 +113,7 @@
flags['fresh_virtualizable'] = True
s_x = annmodel.SomeInstance(s_x.classdef,
s_x.can_be_None,
- flags)
+ flags)
return s_x
def specialize_call(self, hop, **kwds_i):
@@ -179,29 +179,10 @@
pass
-##def force_virtualizable(virtualizable):
-## pass
-
-##class Entry(ExtRegistryEntry):
-## _about_ = force_virtualizable
-
-## def compute_result_annotation(self):
-## from pypy.annotation import model as annmodel
-## return annmodel.s_None
-
-## def specialize_call(self, hop):
-## [vinst] = hop.inputargs(hop.args_r[0])
-## cname = inputconst(lltype.Void, None)
-## cflags = inputconst(lltype.Void, {})
-## hop.exception_cannot_occur()
-## return hop.genop('jit_force_virtualizable', [vinst, cname, cflags],
-## resulttype=lltype.Void)
-
# ____________________________________________________________
# VRefs
def virtual_ref(x):
-
"""Creates a 'vref' object that contains a reference to 'x'. Calls
to virtual_ref/virtual_ref_finish must be properly nested. The idea
is that the object 'x' is supposed to be JITted as a virtual between
@@ -212,10 +193,10 @@
return DirectJitVRef(x)
virtual_ref.oopspec = 'virtual_ref(x)'
-def virtual_ref_finish(x):
- """See docstring in virtual_ref(x). Note that virtual_ref_finish
- takes as argument the real object, not the vref."""
+def virtual_ref_finish(vref, x):
+ """See docstring in virtual_ref(x)"""
keepalive_until_here(x) # otherwise the whole function call is removed
+ _virtual_ref_finish(vref, x)
virtual_ref_finish.oopspec = 'virtual_ref_finish(x)'
def non_virtual_ref(x):
@@ -223,19 +204,39 @@
Used for None or for frames outside JIT scope."""
return DirectVRef(x)
+class InvalidVirtualRef(Exception):
+ """
+ Raised if we try to call a non-forced virtualref after the call to
+ virtual_ref_finish
+ """
+
# ---------- implementation-specific ----------
class DirectVRef(object):
def __init__(self, x):
self._x = x
+ self._state = 'non-forced'
+
def __call__(self):
+ if self._state == 'non-forced':
+ self._state = 'forced'
+ elif self._state == 'invalid':
+ raise InvalidVirtualRef
return self._x
+ def _finish(self):
+ if self._state == 'non-forced':
+ self._state = 'invalid'
+
class DirectJitVRef(DirectVRef):
def __init__(self, x):
assert x is not None, "virtual_ref(None) is not allowed"
DirectVRef.__init__(self, x)
+def _virtual_ref_finish(vref, x):
+ assert vref._x is x, "Invalid call to virtual_ref_finish"
+ vref._finish()
+
class Entry(ExtRegistryEntry):
_about_ = (non_virtual_ref, DirectJitVRef)
@@ -255,17 +256,26 @@
s_obj = self.bookkeeper.immutablevalue(self.instance())
return _jit_vref.SomeVRef(s_obj)
+class Entry(ExtRegistryEntry):
+ _about_ = _virtual_ref_finish
+
+ def compute_result_annotation(self, s_vref, s_obj):
+ pass
+
+ def specialize_call(self, hop):
+ pass
+
vref_None = non_virtual_ref(None)
# ____________________________________________________________
-# User interface for the hotpath JIT policy
+# User interface for the warmspot JIT policy
class JitHintError(Exception):
"""Inconsistency in the JIT hints."""
PARAMETERS = {'threshold': 1000,
'trace_eagerness': 200,
- 'trace_limit': 10000,
+ 'trace_limit': 12000,
'inlining': 0,
'loop_longevity': 1000,
'retrace_limit': 5,
@@ -275,7 +285,7 @@
# ____________________________________________________________
-class JitDriver(object):
+class JitDriver(object):
"""Base class to declare fine-grained user control on the JIT. So
far, there must be a singleton instance of JitDriver. This style
will allow us (later) to support a single RPython program with
@@ -360,6 +370,24 @@
raise
set_user_param._annspecialcase_ = 'specialize:arg(0)'
+
+ def on_compile(self, logger, looptoken, operations, type, *greenargs):
+ """ A hook called when loop is compiled. Overwrite
+ for your own jitdriver if you want to do something special, like
+ call applevel code
+ """
+
+ def on_compile_bridge(self, logger, orig_looptoken, operations, n):
+ """ A hook called when a bridge is compiled. Overwrite
+ for your own jitdriver if you want to do something special
+ """
+
+ # note: if you overwrite this functions with the above signature it'll
+ # work, but the *greenargs is different for each jitdriver, so we
+ # can't share the same methods
+ del on_compile
+ del on_compile_bridge
+
def _make_extregistryentries(self):
# workaround: we cannot declare ExtRegistryEntries for functions
# used as methods of a frozen object, but we can attach the
@@ -477,8 +505,6 @@
r_green = hop.args_r[i]
v_green = hop.inputarg(r_green, arg=i)
else:
- #if hop.rtyper.type_system.name == 'ootypesystem':
- #py.test.skip("lltype only")
objname, fieldname = name.split('.') # see test_green_field
assert objname in driver.reds
i = kwds_i['i_' + objname]
@@ -557,7 +583,7 @@
def specialize_call(self, hop):
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.lltypesystem.rstr import string_repr
-
+
hop.exception_cannot_occur()
driver = self.instance.im_self
name = hop.args_s[0].const
diff --git a/pypy/rlib/nonconst.py b/pypy/rlib/nonconst.py
--- a/pypy/rlib/nonconst.py
+++ b/pypy/rlib/nonconst.py
@@ -18,6 +18,12 @@
def __nonzero__(self):
return bool(self.__dict__['constant'])
+ def __eq__(self, other):
+ return self.__dict__['constant'] == other
+
+ def __add__(self, other):
+ return self.__dict__['constant'] + other
+
class EntryNonConstant(ExtRegistryEntry):
_about_ = NonConstant
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -1345,6 +1345,7 @@
# XXX make sure that we don't ignore this!
# YYY no, we decided to do ignore this!
+ at jit.dont_look_inside
def _AsDouble(n):
""" Get a C double from a bigint object. """
# This is a "correctly-rounded" version from Python 2.7.
diff --git a/pypy/rlib/rcoroutine.py b/pypy/rlib/rcoroutine.py
--- a/pypy/rlib/rcoroutine.py
+++ b/pypy/rlib/rcoroutine.py
@@ -29,7 +29,7 @@
The type of a switch is determined by the target's costate.
"""
-from pypy.rlib.rstack import yield_current_frame_to_caller, resume_point
+from pypy.rlib.rstack import yield_current_frame_to_caller
from pypy.rlib.objectmodel import we_are_translated
from pypy.interpreter.error import OperationError
@@ -228,7 +228,6 @@
self.thunk = None
syncstate.switched(incoming_frame)
thunk.call()
- resume_point("coroutine__bind", state)
except Exception, e:
exc = e
raise
@@ -257,7 +256,6 @@
raise CoroutineDamage
state = self.costate
incoming_frame = state.update(self).switch()
- resume_point("coroutine_switch", state, returns=incoming_frame)
syncstate.switched(incoming_frame)
def kill(self):
diff --git a/pypy/rlib/rsre/rsre_core.py b/pypy/rlib/rsre/rsre_core.py
--- a/pypy/rlib/rsre/rsre_core.py
+++ b/pypy/rlib/rsre/rsre_core.py
@@ -759,17 +759,27 @@
@specializectx
def find_repetition_end(ctx, ppos, ptr, maxcount):
end = ctx.end
- if maxcount <= 1:
- if maxcount == 1 and ptr < end:
- # Relatively common case: maxcount == 1. If we are not at the
- # end of the string, it's done by a single direct check.
- op = ctx.pat(ppos)
- for op1, checkerfn in unroll_char_checker:
- if op1 == op:
- if checkerfn(ctx, ptr, ppos):
- return ptr + 1
+ ptrp1 = ptr + 1
+ # First get rid of the cases where we don't have room for any match.
+ if maxcount <= 0 or ptrp1 > end:
return ptr
- elif maxcount != 65535:
+ # Check the first character directly. If it doesn't match, we are done.
+ # The idea is to be fast for cases like re.search("b+"), where we expect
+ # the common case to be a non-match. It's much faster with the JIT to
+ # have the non-match inlined here rather than detect it in the fre() call.
+ op = ctx.pat(ppos)
+ for op1, checkerfn in unroll_char_checker:
+ if op1 == op:
+ if checkerfn(ctx, ptr, ppos):
+ break
+ else:
+ return ptr
+ # It matches at least once. If maxcount == 1 (relatively common),
+ # then we are done.
+ if maxcount == 1:
+ return ptrp1
+ # Else we really need to count how many times it matches.
+ if maxcount != 65535:
# adjust end
end1 = ptr + maxcount
if end1 <= end:
@@ -777,7 +787,7 @@
op = ctx.pat(ppos)
for op1, fre in unroll_fre_checker:
if op1 == op:
- return fre(ctx, ptr, end, ppos)
+ return fre(ctx, ptrp1, end, ppos)
raise Error("rsre.find_repetition_end[%d]" % op)
@specializectx
diff --git a/pypy/rlib/rsre/test/test_zjit.py b/pypy/rlib/rsre/test/test_zjit.py
--- a/pypy/rlib/rsre/test/test_zjit.py
+++ b/pypy/rlib/rsre/test/test_zjit.py
@@ -160,3 +160,9 @@
res = self.meta_interp_match(r"<[\S ]+>", "<..a .. aa>")
assert res == 13
self.check_enter_count(1)
+
+
+ def test_find_repetition_end_fastpath(self):
+ res = self.meta_interp_search(r"b+", "a"*30 + "b")
+ assert res == 30
+ self.check_loops(call=0)
diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py
--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -42,16 +42,26 @@
sandboxsafe=True, _nowrapper=True,
_callable=_callable)
-_stack_get_start = llexternal('LL_stack_get_start', [], lltype.Signed,
- lambda: 0)
+_stack_get_end = llexternal('LL_stack_get_end', [], lltype.Signed,
+ lambda: 0)
_stack_get_length = llexternal('LL_stack_get_length', [], lltype.Signed,
lambda: 1)
+_stack_set_length_fraction = llexternal('LL_stack_set_length_fraction',
+ [lltype.Float], lltype.Void,
+ lambda frac: None)
_stack_too_big_slowpath = llexternal('LL_stack_too_big_slowpath',
[lltype.Signed], lltype.Char,
lambda cur: '\x00')
# the following is used by the JIT
-_stack_get_start_adr = llexternal('LL_stack_get_start_adr', [], lltype.Signed)
+_stack_get_end_adr = llexternal('LL_stack_get_end_adr', [], lltype.Signed)
+_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed)
+# the following is also used by the JIT: "critical code" paths are paths in
+# which we should not raise StackOverflow at all, but just ignore the stack limit
+_stack_criticalcode_start = llexternal('LL_stack_criticalcode_start', [],
+ lltype.Void, lambda: None)
+_stack_criticalcode_stop = llexternal('LL_stack_criticalcode_stop', [],
+ lltype.Void, lambda: None)
def stack_check():
if not we_are_translated():
@@ -62,13 +72,13 @@
current = llop.stack_current(lltype.Signed)
#
# Load these variables from C code
- start = _stack_get_start()
+ end = _stack_get_end()
length = _stack_get_length()
#
- # Common case: if 'current' is within [start:start+length], everything
+ # Common case: if 'current' is within [end-length:end], everything
# is fine
- ofs = r_uint(current - start)
- if ofs < r_uint(length):
+ ofs = r_uint(end - current)
+ if ofs <= r_uint(length):
return
#
# Else call the slow path
@@ -140,111 +150,6 @@
return var
-def resume_point(label, *args, **kwds):
- pass
-
-
-
-class ResumePointFnEntry(ExtRegistryEntry):
- _about_ = resume_point
-
- def compute_result_annotation(self, s_label, *args_s, **kwds_s):
- from pypy.annotation import model as annmodel
- return annmodel.s_None
-
- def specialize_call(self, hop, **kwds_i):
- from pypy.rpython.lltypesystem import lltype
- from pypy.objspace.flow import model
-
- assert hop.args_s[0].is_constant()
- c_label = hop.inputconst(lltype.Void, hop.args_s[0].const)
- args_v = hop.args_v[1:]
- if 'i_returns' in kwds_i:
- assert len(kwds_i) == 1
- returns_index = kwds_i['i_returns']
- v_return = args_v.pop(returns_index-1)
- assert isinstance(v_return, model.Variable), \
- "resume_point returns= argument must be a Variable"
- else:
- assert not kwds_i
- v_return = hop.inputconst(lltype.Void, None)
-
- for v in args_v:
- assert isinstance(v, model.Variable), "resume_point arguments must be Variables"
-
- hop.exception_is_here()
- return hop.genop('resume_point', [c_label, v_return] + args_v,
- hop.r_result)
-
-def resume_state_create(prevstate, label, *args):
- raise RuntimeError("cannot resume states in non-translated versions")
-
-def concretify_argument(hop, index):
- from pypy.objspace.flow import model
-
- v_arg = hop.args_v[index]
- if isinstance(v_arg, model.Variable):
- return v_arg
-
- r_arg = hop.rtyper.bindingrepr(v_arg)
- return hop.inputarg(r_arg, arg=index)
-
-class ResumeStateCreateFnEntry(FrameStackTopReturningFnEntry):
- _about_ = resume_state_create
-
- def compute_result_annotation(self, s_prevstate, s_label, *args_s):
- return FrameStackTopReturningFnEntry.compute_result_annotation(self)
-
- def specialize_call(self, hop):
- from pypy.rpython.lltypesystem import lltype
-
- assert hop.args_s[1].is_constant()
- c_label = hop.inputconst(lltype.Void, hop.args_s[1].const)
-
- v_state = hop.inputarg(hop.r_result, arg=0)
-
- args_v = []
- for i in range(2, len(hop.args_v)):
- args_v.append(concretify_argument(hop, i))
-
- hop.exception_is_here()
- return hop.genop('resume_state_create', [v_state, c_label] + args_v,
- hop.r_result)
-
-def resume_state_invoke(type, state, **kwds):
- raise NotImplementedError("only works in translated versions")
-
-class ResumeStateInvokeFnEntry(ExtRegistryEntry):
- _about_ = resume_state_invoke
-
- def compute_result_annotation(self, s_type, s_state, **kwds):
- from pypy.annotation.bookkeeper import getbookkeeper
- assert s_type.is_constant()
- return getbookkeeper().valueoftype(s_type.const)
-
- def specialize_call(self, hop, **kwds_i):
- from pypy.rpython.lltypesystem import lltype
- v_state = hop.args_v[1]
-
- if 'i_returning' in kwds_i:
- assert len(kwds_i) == 1
- returning_index = kwds_i['i_returning']
- v_returning = concretify_argument(hop, returning_index)
- v_raising = hop.inputconst(lltype.Void, None)
- elif 'i_raising' in kwds_i:
- assert len(kwds_i) == 1
- raising_index = kwds_i['i_raising']
- v_returning = hop.inputconst(lltype.Void, None)
- v_raising = concretify_argument(hop, raising_index)
- else:
- assert not kwds_i
- v_returning = hop.inputconst(lltype.Void, None)
- v_raising = hop.inputconst(lltype.Void, None)
-
- hop.exception_is_here()
- return hop.genop('resume_state_invoke', [v_state, v_returning, v_raising],
- hop.r_result)
-
# ____________________________________________________________
def get_stack_depth_limit():
diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py
--- a/pypy/rlib/test/test__jit_vref.py
+++ b/pypy/rlib/test/test__jit_vref.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import virtual_ref, virtual_ref_finish
-from pypy.rlib.jit import vref_None, non_virtual_ref
+from pypy.rlib.jit import vref_None, non_virtual_ref, InvalidVirtualRef
from pypy.rlib._jit_vref import SomeVRef
from pypy.annotation import model as annmodel
from pypy.annotation.annrpython import RPythonAnnotator
@@ -23,18 +23,23 @@
pass
-def test_direct_1():
+def test_direct_forced():
x1 = X()
vref = virtual_ref(x1)
+ assert vref._state == 'non-forced'
assert vref() is x1
- virtual_ref_finish(x1)
+ assert vref._state == 'forced'
+ virtual_ref_finish(vref, x1)
+ assert vref._state == 'forced'
assert vref() is x1
-def test_direct_2():
+def test_direct_invalid():
x1 = X()
vref = virtual_ref(x1)
- virtual_ref_finish(x1)
- assert vref() is x1
+ assert vref._state == 'non-forced'
+ virtual_ref_finish(vref, x1)
+ assert vref._state == 'invalid'
+ py.test.raises(InvalidVirtualRef, "vref()")
def test_annotate_1():
def f():
@@ -50,7 +55,7 @@
x1 = X()
vref = virtual_ref(x1)
x2 = vref()
- virtual_ref_finish(x1)
+ virtual_ref_finish(vref, x1)
return x2
a = RPythonAnnotator()
s = a.build_types(f, [])
@@ -95,7 +100,7 @@
x1 = X()
vref = virtual_ref(x1)
x2 = vref()
- virtual_ref_finish(x2)
+ virtual_ref_finish(vref, x2)
return x2
x = self.interpret(f, [])
assert self.castable(self.OBJECTTYPE, x)
@@ -119,6 +124,18 @@
assert lltype.typeOf(x) == self.OBJECTTYPE
assert not x
+ def test_rtype_5(self):
+ def f():
+ vref = virtual_ref(X())
+ try:
+ vref()
+ return 42
+ except InvalidVirtualRef:
+ return -1
+ x = self.interpret(f, [])
+ assert x == 42
+
+
class TestLLtype(BaseTestVRef, LLRtypeMixin):
OBJECTTYPE = OBJECTPTR
def castable(self, TO, var):
diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py
--- a/pypy/rlib/test/test_debug.py
+++ b/pypy/rlib/test/test_debug.py
@@ -2,7 +2,7 @@
import py
from pypy.rlib.debug import check_annotation, make_sure_not_resized
from pypy.rlib.debug import debug_print, debug_start, debug_stop
-from pypy.rlib.debug import have_debug_prints
+from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush
from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative
from pypy.rlib import debug
from pypy.rpython.test.test_llinterp import interpret
@@ -60,6 +60,8 @@
debug_start("mycat")
debug_print("foo", 2, "bar", x)
debug_stop("mycat")
+ debug_flush() # does nothing
+ debug_offset() # should not explode at least
return have_debug_prints()
try:
diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py
--- a/pypy/rlib/test/test_jit.py
+++ b/pypy/rlib/test/test_jit.py
@@ -52,9 +52,12 @@
import sys
s = StringIO()
+ prev = sys.stdout
sys.stdout = s
- dis.dis(g)
- sys.stdout = sys.__stdout__
+ try:
+ dis.dis(g)
+ finally:
+ sys.stdout = prev
x = s.getvalue().find('CALL_FUNCTION')
assert x != -1
x = s.getvalue().find('CALL_FUNCTION', x)
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -513,13 +513,6 @@
from pypy.translator.tool.lltracker import track
track(*ll_objects)
- def op_debug_pdb(self, *ll_args):
- if self.llinterpreter.tracer:
- self.llinterpreter.tracer.flush()
- print "entering pdb...", ll_args
- import pdb
- pdb.set_trace()
-
def op_debug_assert(self, x, msg):
assert x, msg
@@ -570,15 +563,6 @@
def op_hint(self, x, hints):
return x
- def op_resume_point(self, *args):
- pass
-
- def op_resume_state_create(self, *args):
- raise RuntimeError("resume_state_create can not be called.")
-
- def op_resume_state_invoke(self, *args):
- raise RuntimeError("resume_state_invoke can not be called.")
-
def op_decode_arg(self, fname, i, name, vargs, vkwds):
raise NotImplementedError("decode_arg")
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -20,7 +20,6 @@
from pypy.rpython.extfunc import ExtRegistryEntry
from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
from pypy.tool.uid import fixid
-from pypy.tool.tls import tlsobject
from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, intmask
from pypy.annotation import model as annmodel
from pypy.rpython.llinterp import LLInterpreter, LLException
@@ -28,6 +27,7 @@
from pypy.rpython import raddress
from pypy.translator.platform import platform
from array import array
+from thread import _local as tlsobject
# ____________________________________________________________
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -521,10 +521,6 @@
RuntimeError)),
# can always unwind, not just if stackless gc
- 'resume_point': LLOp(canraise=(Exception,)),
- 'resume_state_create': LLOp(canraise=(MemoryError,), canunwindgc=True),
- 'resume_state_invoke': LLOp(canraise=(Exception, StackException,
- RuntimeError)),
'stack_frames_depth': LLOp(sideeffects=False, canraise=(StackException,
RuntimeError)),
'stack_switch': LLOp(canraise=(StackException, RuntimeError)),
@@ -553,7 +549,8 @@
'debug_start': LLOp(canrun=True),
'debug_stop': LLOp(canrun=True),
'have_debug_prints': LLOp(canrun=True),
- 'debug_pdb': LLOp(),
+ 'debug_offset': LLOp(canrun=True),
+ 'debug_flush': LLOp(canrun=True),
'debug_assert': LLOp(tryfold=True),
'debug_fatalerror': LLOp(),
'debug_llinterpcall': LLOp(canraise=(Exception,)),
diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py
--- a/pypy/rpython/lltypesystem/lltype.py
+++ b/pypy/rpython/lltypesystem/lltype.py
@@ -4,14 +4,16 @@
base_int, normalizedinttype)
from pypy.rlib.objectmodel import Symbolic
from pypy.tool.uid import Hashable
-from pypy.tool.tls import tlsobject
from pypy.tool.identity_dict import identity_dict
from pypy.tool import leakfinder
from types import NoneType
from sys import maxint
import weakref
-TLS = tlsobject()
+class State(object):
+ pass
+
+TLS = State()
class WeakValueDictionary(weakref.WeakValueDictionary):
"""A subclass of weakref.WeakValueDictionary
diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -513,6 +513,12 @@
def op_debug_stop(category):
debug.debug_stop(_normalize(category))
+def op_debug_offset():
+ return debug.debug_offset()
+
+def op_debug_flush():
+ pass
+
def op_have_debug_prints():
return debug.have_debug_prints()
diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py
--- a/pypy/rpython/lltypesystem/rlist.py
+++ b/pypy/rpython/lltypesystem/rlist.py
@@ -237,6 +237,7 @@
l.length = newsize
else:
_ll_list_resize_really(l, newsize)
+_ll_list_resize_ge.oopspec = 'list._resize_ge(l, newsize)'
def _ll_list_resize_le(l, newsize):
if newsize >= (len(l.items) >> 1) - 5:
diff --git a/pypy/rpython/lltypesystem/rpbc.py b/pypy/rpython/lltypesystem/rpbc.py
--- a/pypy/rpython/lltypesystem/rpbc.py
+++ b/pypy/rpython/lltypesystem/rpbc.py
@@ -198,7 +198,6 @@
inputargs = [varoftype(t) for t in [Char] + argtypes]
startblock = Block(inputargs)
startblock.exitswitch = inputargs[0]
- #startblock.operations.append(SpaceOperation('debug_pdb', [], varoftype(Void)))
graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
row_of_graphs = self.callfamily.calltables[shape][index]
links = []
diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py
--- a/pypy/rpython/rlist.py
+++ b/pypy/rpython/rlist.py
@@ -568,7 +568,6 @@
length = l.ll_length()
l._ll_resize_ge(length+1) # see "a note about overflows" above
l.ll_setitem_fast(length, newitem)
-ll_append.oopspec = 'list.append(l, newitem)'
# this one is for the special case of insert(0, x)
def ll_prepend(l, newitem):
@@ -793,7 +792,6 @@
raise MemoryError
l1._ll_resize_ge(newlength)
ll_arraycopy(l2, l1, 0, len1, len2)
-ll_extend.oopspec = 'list.extend(l1, l2)'
def ll_extend_with_str(lst, s, getstrlen, getstritem):
return ll_extend_with_str_slice_startonly(lst, s, getstrlen, getstritem, 0)
diff --git a/pypy/tool/memusage/__init__.py b/pypy/tool/memusage/__init__.py
new file mode 100644
diff --git a/pypy/jit/tool/log-template.gnumeric b/pypy/tool/memusage/log-template.gnumeric
rename from pypy/jit/tool/log-template.gnumeric
rename to pypy/tool/memusage/log-template.gnumeric
diff --git a/pypy/jit/tool/log2gnumeric.py b/pypy/tool/memusage/log2gnumeric.py
old mode 100644
new mode 100755
rename from pypy/jit/tool/log2gnumeric.py
rename to pypy/tool/memusage/log2gnumeric.py
--- a/pypy/jit/tool/log2gnumeric.py
+++ b/pypy/tool/memusage/log2gnumeric.py
@@ -1,12 +1,34 @@
#! /usr/bin/env python
"""
-Usage: log2gnumeric logfile
-
Produces a logfile.gnumeric file which contains the data extracted from the
logfile generated with the PYPYLOG env variable.
-Currently, it expects log to contain the translation-task and gc-collect
-categories.
+Run your program like this::
+
+ $ PYPYLOG=gc-collect,jit-mem:logfile pypy your-program.py
+
+This will produce "logfile", containing informations about the memory used by
+the GC and the number of loops created/freed by the JIT.
+
+If you want, you can also measure the amout of used memory as seen by the OS
+(the VmRSS) using memusage.py::
+
+ $ PYPYLOG=gc-collect,jit-mem:logfile ./memusage.py -o logfile.vmrss /path/to/pypy your-program.py
+
+log2gnumeric will automatically pick logfile.vmrss, if present.
+
+If you want to compare PyPy to CPython, you can add its VmRSS to the graph, by
+using the -c option. To produce the .vmrss file, use again ./memusage.py::
+
+ $ ./memusage.py -o cpython.vmrss python your-program.py
+ $ ./log2gnumeric.py -c cpython.vmrss logfile
+
+Note that on CPython it will take a different amout of time to complete, but
+on the graph the plot will be scaled to match the duration of the PyPy run
+(i.e., the two lines will end "at the same time").
+
+If you are benchmarking translate.py, you can add the "translation-task"
+category to the log, by setting PYPYLOG=gc-collect,jit-mem,translation-task.
You can freely edit the graph in log-template.gnumeric: this script will
create a new file replacing the 'translation-task' and 'gc-collect' sheets.
@@ -18,7 +40,6 @@
def main(logname, options):
- logname = sys.argv[1]
outname = logname + '.gnumeric'
data = open(logname).read()
data = data.replace('\n', '')
@@ -151,11 +172,11 @@
def vmrss_rows(filename, maxtime):
lines = []
- if options.cpython_vmrss:
+ if filename:
try:
lines = open(filename).readlines()
except IOError:
- print 'Warning: cannot find file %s, skipping this sheet'
+ print 'Warning: cannot find file %s, skipping this sheet' % filename
for row in vmrss_rows_impl(lines, maxtime):
yield row
@@ -171,8 +192,11 @@
if __name__ == '__main__':
CLOCK_FACTOR = 1000000000.0 # report GigaTicks instead of Ticks
parser = optparse.OptionParser(usage="%prog logfile [options]")
+ parser.format_description = lambda fmt: __doc__
+ parser.description = __doc__
parser.add_option('-c', '--cpython-vmrss', dest='cpython_vmrss', default=None, metavar='FILE', type=str,
help='the .vmrss file produced by CPython')
+
options, args = parser.parse_args()
if len(args) != 1:
parser.print_help()
diff --git a/pypy/tool/memusage/memusage.py b/pypy/tool/memusage/memusage.py
new file mode 100755
--- /dev/null
+++ b/pypy/tool/memusage/memusage.py
@@ -0,0 +1,63 @@
+#! /usr/bin/env python
+"""
+Usage: memusage.py [-o filename] command [args...]
+
+Runs a subprocess, and measure its RSS (resident set size) every second.
+At the end, print the maximum RSS measured, and some statistics.
+
+Also writes "filename", reporting every second the RSS. If filename is not
+given, the output is written to "memusage.log"
+"""
+
+import sys, os, re, time
+
+def parse_args():
+ args = sys.argv[1:]
+ if args[0] == '-o':
+ args.pop(0)
+ outname = args.pop(0)
+ else:
+ outname = 'memusage.log'
+ args[0] # make sure there is at least one argument left
+ return outname, args
+
+try:
+ outname, args = parse_args()
+except IndexError:
+ print >> sys.stderr, __doc__.strip()
+ sys.exit(2)
+
+childpid = os.fork()
+if childpid == 0:
+ os.execvp(args[0], args)
+ sys.exit(1)
+
+r = re.compile("VmRSS:\s*(\d+)")
+
+filename = '/proc/%d/status' % childpid
+rss_max = 0
+rss_sum = 0
+rss_count = 0
+
+f = open(outname, 'w', 0)
+while os.waitpid(childpid, os.WNOHANG)[0] == 0:
+ g = open(filename)
+ s = g.read()
+ g.close()
+ match = r.search(s)
+ if not match: # VmRSS is missing if the process just finished
+ break
+ rss = int(match.group(1))
+ print >> f, rss
+ if rss > rss_max: rss_max = rss
+ rss_sum += rss
+ rss_count += 1
+ time.sleep(1)
+f.close()
+
+if rss_count > 0:
+ print
+ print 'Memory usage:'
+ print '\tmaximum RSS: %10d kb' % rss_max
+ print '\tmean RSS: %10d kb' % (rss_sum / rss_count)
+ print '\trun time: %10d s' % rss_count
diff --git a/pypy/jit/tool/test/test_log2gnumeric.py b/pypy/tool/memusage/test/test_log2gnumeric.py
rename from pypy/jit/tool/test/test_log2gnumeric.py
rename to pypy/tool/memusage/test/test_log2gnumeric.py
--- a/pypy/jit/tool/test/test_log2gnumeric.py
+++ b/pypy/tool/memusage/test/test_log2gnumeric.py
@@ -1,4 +1,4 @@
-from pypy.jit.tool import log2gnumeric
+from pypy.tool.memusage import log2gnumeric
log = """
[1000] ...
diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py
--- a/pypy/tool/pytest/appsupport.py
+++ b/pypy/tool/pytest/appsupport.py
@@ -81,7 +81,7 @@
self.space = space
self.operr = operr
self.typename = operr.w_type.getname(space, "?")
- self.traceback = AppTraceback(space, self.operr.application_traceback)
+ self.traceback = AppTraceback(space, self.operr.get_traceback())
debug_excs = getattr(operr, 'debug_excs', [])
if debug_excs:
self._excinfo = debug_excs[0]
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -36,6 +36,10 @@
class PyPyCNotFound(Exception):
pass
+def fix_permissions(basedir):
+ if sys.platform != 'win32':
+ os.system("chmod -R a+rX %s" % basedir)
+
def package(basedir, name='pypy-nightly', rename_pypy_c='pypy',
copy_to_dir = None, override_pypy_c = None):
basedir = py.path.local(basedir)
@@ -93,6 +97,7 @@
archive = bindir.join(target)
shutil.copy(str(source), str(archive))
old_dir = os.getcwd()
+ fix_permissions(builddir)
try:
os.chdir(str(builddir))
#
@@ -117,7 +122,7 @@
zf.close()
else:
archive = str(builddir.join(name + '.tar.bz2'))
- e = os.system('tar cvjf ' + archive + " " + name)
+ e = os.system('tar --owner=root --group=root --numeric-owner -cvjf ' + archive + " " + name)
if e:
raise OSError('"tar" returned exit status %r' % e)
finally:
diff --git a/pypy/tool/release/test/test_package.py b/pypy/tool/release/test/test_package.py
--- a/pypy/tool/release/test/test_package.py
+++ b/pypy/tool/release/test/test_package.py
@@ -10,12 +10,15 @@
if sys.platform == 'win32':
basename = 'pypy-c.exe'
rename_pypy_c = 'pypy-c'
+ exe_name_in_archive = 'pypy-c.exe'
else:
basename = 'pypy-c'
rename_pypy_c = 'pypy'
+ exe_name_in_archive = 'bin/pypy'
pypy_c = py.path.local(pypydir).join('translator', 'goal', basename)
if not pypy_c.check():
os.system("echo faked_pypy_c> %s" % (pypy_c,))
+ pypy_c.chmod(0755)
fake_pypy_c = True
else:
fake_pypy_c = False
@@ -25,10 +28,7 @@
prefix = builddir.join(test)
cpyver = '%d.%d' % CPYTHON_VERSION[:2]
assert prefix.join('lib-python', cpyver, 'test').check()
- if sys.platform == 'win32':
- assert prefix.join('pypy-c.exe').check()
- else:
- assert prefix.join('bin', 'pypy').check()
+ assert prefix.join(exe_name_in_archive).check()
assert prefix.join('lib_pypy', 'syslog.py').check()
assert not prefix.join('lib_pypy', 'py').check()
assert not prefix.join('lib_pypy', 'ctypes_configure').check()
@@ -39,7 +39,14 @@
assert zh.open('%s/lib_pypy/syslog.py' % test)
else:
th = tarfile.open(str(builddir.join('%s.tar.bz2' % test)))
- assert th.getmember('%s/lib_pypy/syslog.py' % test)
+ syslog = th.getmember('%s/lib_pypy/syslog.py' % test)
+ exe = th.getmember('%s/%s' % (test, exe_name_in_archive))
+ assert syslog.mode == 0644
+ assert exe.mode == 0755
+ assert exe.uname == ''
+ assert exe.gname == ''
+ assert exe.uid == 0
+ assert exe.gid == 0
# the headers file could be not there, because they are copied into
# trunk/include only during translation
@@ -66,3 +73,26 @@
test_dir_structure(test='testzipfile')
finally:
package.USE_ZIPFILE_MODULE = prev
+
+def test_fix_permissions(tmpdir):
+ def check(f, mode):
+ assert f.stat().mode & 0777 == mode
+ #
+ mydir = tmpdir.join('mydir').ensure(dir=True)
+ bin = tmpdir.join('bin') .ensure(dir=True)
+ file1 = tmpdir.join('file1').ensure(file=True)
+ file2 = mydir .join('file2').ensure(file=True)
+ pypy = bin .join('pypy') .ensure(file=True)
+ #
+ mydir.chmod(0700)
+ bin.chmod(0700)
+ file1.chmod(0600)
+ file2.chmod(0640)
+ pypy.chmod(0700)
+ #
+ package.fix_permissions(tmpdir)
+ check(mydir, 0755)
+ check(bin, 0755)
+ check(file1, 0644)
+ check(file2, 0644)
+ check(pypy, 0755)
diff --git a/pypy/tool/tls.py b/pypy/tool/tls.py
deleted file mode 100644
--- a/pypy/tool/tls.py
+++ /dev/null
@@ -1,8 +0,0 @@
-
-"""Thread-local storage."""
-
-try:
- from thread import _local as tlsobject
-except ImportError:
- class tlsobject(object):
- pass
diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py
--- a/pypy/translator/backendopt/inline.py
+++ b/pypy/translator/backendopt/inline.py
@@ -541,7 +541,6 @@
'cast_pointer': 0,
'malloc': 2,
'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme
- 'resume_point': sys.maxint, # XXX bit extreme
'instrument_count': 0,
'debug_assert': -1,
}
diff --git a/pypy/translator/backendopt/removenoops.py b/pypy/translator/backendopt/removenoops.py
--- a/pypy/translator/backendopt/removenoops.py
+++ b/pypy/translator/backendopt/removenoops.py
@@ -81,8 +81,6 @@
num_removed += 1
else:
available[key] = op.result
- elif op.opname == 'resume_point':
- available.clear()
if num_removed:
remove_same_as(graph)
# remove casts with unused results
diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py
--- a/pypy/translator/c/funcgen.py
+++ b/pypy/translator/c/funcgen.py
@@ -705,7 +705,7 @@
offset = self.expr(op.args[2])
value = self.expr(op.args[3])
typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '')
- return "*(((%(typename)s) %(addr)s ) + %(offset)s) = %(value)s;" % locals()
+ return "((%(typename)s) %(addr)s)[%(offset)s] = %(value)s;" % locals()
def OP_RAW_LOAD(self, op):
addr = self.expr(op.args[0])
@@ -713,7 +713,7 @@
offset = self.expr(op.args[2])
result = self.expr(op.result)
typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '')
- return "%(result)s = *(((%(typename)s) %(addr)s ) + %(offset)s);" % locals()
+ return "%(result)s = ((%(typename)s) %(addr)s)[%(offset)s];" % locals()
def OP_CAST_PRIMITIVE(self, op):
TYPE = self.lltypemap(op.result)
diff --git a/pypy/translator/c/src/debug_print.c b/pypy/translator/c/src/debug_print.c
--- a/pypy/translator/c/src/debug_print.c
+++ b/pypy/translator/c/src/debug_print.c
@@ -6,6 +6,8 @@
#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -65,6 +67,15 @@
debug_ready = 1;
}
+long pypy_debug_offset(void)
+{
+ if (!debug_ready)
+ return -1;
+ // note that we deliberately ignore errno, since -1 is fine
+ // in case this is not a real file
+ return ftell(pypy_debug_file);
+}
+
void pypy_debug_ensure_opened(void)
{
if (!debug_ready)
diff --git a/pypy/translator/c/src/debug_print.h b/pypy/translator/c/src/debug_print.h
--- a/pypy/translator/c/src/debug_print.h
+++ b/pypy/translator/c/src/debug_print.h
@@ -26,8 +26,9 @@
#define PYPY_DEBUG_FILE pypy_debug_file
#define PYPY_DEBUG_START(cat) pypy_debug_start(cat)
#define PYPY_DEBUG_STOP(cat) pypy_debug_stop(cat)
+#define OP_DEBUG_OFFSET(res) res = pypy_debug_offset()
#define OP_HAVE_DEBUG_PRINTS(r) r = (pypy_have_debug_prints & 1)
-
+#define OP_DEBUG_FLUSH() fflush(pypy_debug_file)
/************************************************************/
@@ -35,6 +36,7 @@
void pypy_debug_ensure_opened(void);
void pypy_debug_start(const char *category);
void pypy_debug_stop(const char *category);
+long pypy_debug_offset(void);
extern long pypy_have_debug_prints;
extern FILE *pypy_debug_file;
@@ -51,8 +53,6 @@
# ifdef _WIN32
# define READ_TIMESTAMP(val) QueryPerformanceCounter((LARGE_INTEGER*)&(val))
# else
-# include <time.h>
-# include <sys/time.h>
long long pypy_read_timestamp();
diff --git a/pypy/translator/c/src/debug_traceback.h b/pypy/translator/c/src/debug_traceback.h
--- a/pypy/translator/c/src/debug_traceback.h
+++ b/pypy/translator/c/src/debug_traceback.h
@@ -21,7 +21,11 @@
line to the f:17/KeyError line.
*/
-#define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */
+#ifdef RPY_LL_ASSERT
+# define PYPY_DEBUG_TRACEBACK_DEPTH 8192 /* a power of two */
+#else
+# define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */
+#endif
#define PYPYDTPOS_RERAISE ((struct pypydtpos_s *) -1)
#define PYPYDTSTORE(loc, etype) \
diff --git a/pypy/translator/c/src/float.h b/pypy/translator/c/src/float.h
--- a/pypy/translator/c/src/float.h
+++ b/pypy/translator/c/src/float.h
@@ -43,3 +43,4 @@
#define OP_CAST_FLOAT_TO_LONGLONG(x,r) r = (long long)(x)
#define OP_CAST_FLOAT_TO_ULONGLONG(x,r) r = (unsigned long long)(x)
#endif
+
diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h
--- a/pypy/translator/c/src/stack.h
+++ b/pypy/translator/c/src/stack.h
@@ -11,15 +11,22 @@
* It is needed to have RPyThreadStaticTLS, too. */
#include "thread.h"
-extern char *_LLstacktoobig_stack_start;
+extern char *_LLstacktoobig_stack_end;
+extern long _LLstacktoobig_stack_length;
+extern char _LLstacktoobig_report_error;
void LL_stack_unwind(void);
char LL_stack_too_big_slowpath(long); /* returns 0 (ok) or 1 (too big) */
+void LL_stack_set_length_fraction(double);
/* some macros referenced from pypy.rlib.rstack */
-#define LL_stack_get_start() ((long)_LLstacktoobig_stack_start)
-#define LL_stack_get_length() MAX_STACK_SIZE
-#define LL_stack_get_start_adr() ((long)&_LLstacktoobig_stack_start) /* JIT */
+#define LL_stack_get_end() ((long)_LLstacktoobig_stack_end)
+#define LL_stack_get_length() _LLstacktoobig_stack_length
+#define LL_stack_get_end_adr() ((long)&_LLstacktoobig_stack_end) /* JIT */
+#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */
+
+#define LL_stack_criticalcode_start() (_LLstacktoobig_report_error = 0)
+#define LL_stack_criticalcode_stop() (_LLstacktoobig_report_error = 1)
#ifdef __GNUC__
@@ -32,93 +39,67 @@
#ifndef PYPY_NOT_MAIN_FILE
#include <stdio.h>
-#ifndef PYPY_NOINLINE
-# if defined __GNUC__
-# define PYPY_NOINLINE __attribute__((noinline))
-# else
-// add hints for other compilers here ...
-# define PYPY_NOINLINE
-# endif
-#endif
+/* the current stack is in the interval [end-length:end]. We assume a
+ stack that grows downward here. */
+char *_LLstacktoobig_stack_end = NULL;
+long _LLstacktoobig_stack_length = MAX_STACK_SIZE;
+char _LLstacktoobig_report_error = 1;
+static RPyThreadStaticTLS end_tls_key;
-long PYPY_NOINLINE _LL_stack_growing_direction(char *parent)
+void LL_stack_set_length_fraction(double fraction)
{
- char local;
- if (parent == NULL)
- return _LL_stack_growing_direction(&local);
- else
- return &local - parent;
+ _LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction);
}
-char *_LLstacktoobig_stack_start = NULL;
-int stack_direction = 0;
-RPyThreadStaticTLS start_tls_key;
-
char LL_stack_too_big_slowpath(long current)
{
- long diff;
+ long diff, max_stack_size;
char *baseptr, *curptr = (char*)current;
- /* The stack_start variable is updated to match the current value
+ /* The stack_end variable is updated to match the current value
if it is still 0 or if we later find a 'curptr' position
- that is below it. The real stack_start pointer is stored in
+ that is above it. The real stack_end pointer is stored in
thread-local storage, but we try to minimize its overhead by
- keeping a local copy in _LLstacktoobig_stack_start. */
+ keeping a local copy in _LLstacktoobig_stack_end. */
- if (stack_direction == 0) {
+ if (_LLstacktoobig_stack_end == NULL) {
/* not initialized */
/* XXX We assume that initialization is performed early,
when there is still only one thread running. This
allows us to ignore race conditions here */
- char *errmsg = RPyThreadStaticTLS_Create(&start_tls_key);
+ char *errmsg = RPyThreadStaticTLS_Create(&end_tls_key);
if (errmsg) {
/* XXX should we exit the process? */
fprintf(stderr, "Internal PyPy error: %s\n", errmsg);
return 1;
}
- if (_LL_stack_growing_direction(NULL) > 0)
- stack_direction = +1;
- else
- stack_direction = -1;
}
- baseptr = (char *) RPyThreadStaticTLS_Get(start_tls_key);
- if (baseptr != NULL) {
- diff = curptr - baseptr;
- if (((unsigned long)diff) < (unsigned long)MAX_STACK_SIZE) {
+ baseptr = (char *) RPyThreadStaticTLS_Get(end_tls_key);
+ max_stack_size = _LLstacktoobig_stack_length;
+ if (baseptr == NULL) {
+ /* first time we see this thread */
+ }
+ else {
+ diff = baseptr - curptr;
+ if (((unsigned long)diff) <= (unsigned long)max_stack_size) {
/* within bounds, probably just had a thread switch */
- _LLstacktoobig_stack_start = baseptr;
+ _LLstacktoobig_stack_end = baseptr;
return 0;
}
-
- if (stack_direction > 0) {
- if (diff < 0 && diff > -MAX_STACK_SIZE)
- ; /* stack underflow */
- else
- return 1; /* stack overflow (probably) */
+ if (((unsigned long)-diff) <= (unsigned long)max_stack_size) {
+ /* stack underflowed: the initial estimation of
+ the stack base must be revised */
}
- else {
- if (diff >= MAX_STACK_SIZE && diff < 2*MAX_STACK_SIZE)
- ; /* stack underflow */
- else
- return 1; /* stack overflow (probably) */
+ else { /* stack overflow (probably) */
+ return _LLstacktoobig_report_error;
}
- /* else we underflowed the stack, which means that
- the initial estimation of the stack base must
- be revised */
}
/* update the stack base pointer to the current value */
- if (stack_direction > 0) {
- /* the valid range is [curptr:curptr+MAX_STACK_SIZE] */
- baseptr = curptr;
- }
- else {
- /* the valid range is [curptr-MAX_STACK_SIZE+1:curptr+1] */
- baseptr = curptr - MAX_STACK_SIZE + 1;
- }
- RPyThreadStaticTLS_Set(start_tls_key, baseptr);
- _LLstacktoobig_stack_start = baseptr;
+ baseptr = curptr;
+ RPyThreadStaticTLS_Set(end_tls_key, baseptr);
+ _LLstacktoobig_stack_end = baseptr;
return 0;
}
diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py
--- a/pypy/translator/c/test/test_standalone.py
+++ b/pypy/translator/c/test/test_standalone.py
@@ -3,8 +3,8 @@
from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rlib.rarithmetic import r_longlong
-from pypy.rlib.debug import ll_assert, have_debug_prints
-from pypy.rlib.debug import debug_print, debug_start, debug_stop
+from pypy.rlib.debug import ll_assert, have_debug_prints, debug_flush
+from pypy.rlib.debug import debug_print, debug_start, debug_stop, debug_offset
from pypy.translator.translator import TranslationContext
from pypy.translator.backendopt import all
from pypy.translator.c.genc import CStandaloneBuilder, ExternalCompilationInfo
@@ -110,6 +110,7 @@
assert counters == (0,3,2)
def test_prof_inline(self):
+ py.test.skip("broken by 5b0e029514d4, but we don't use it any more")
if sys.platform == 'win32':
py.test.skip("instrumentation support is unix only for now")
def add(a,b):
@@ -163,13 +164,13 @@
return 0
from pypy.translator.interactive import Translation
# XXX this is mostly a "does not crash option"
- t = Translation(entry_point, backend='c', standalone=True, profopt="")
+ t = Translation(entry_point, backend='c', standalone=True, profopt="100")
# no counters
t.backendopt()
exe = t.compile()
out = py.process.cmdexec("%s 500" % exe)
assert int(out) == 500*501/2
- t = Translation(entry_point, backend='c', standalone=True, profopt="",
+ t = Translation(entry_point, backend='c', standalone=True, profopt="100",
noprofopt=True)
# no counters
t.backendopt()
@@ -283,12 +284,13 @@
debug_stop ("mycat")
if have_debug_prints(): x += "a"
debug_print("toplevel")
- os.write(1, x + '.\n')
+ debug_flush()
+ os.write(1, x + "." + str(debug_offset()) + '.\n')
return 0
t, cbuilder = self.compile(entry_point)
# check with PYPYLOG undefined
out, err = cbuilder.cmdexec("", err=True, env={})
- assert out.strip() == 'got:a.'
+ assert out.strip() == 'got:a.-1.'
assert 'toplevel' in err
assert 'mycat' not in err
assert 'foo 2 bar 3' not in err
@@ -297,7 +299,7 @@
assert 'bok' not in err
# check with PYPYLOG defined to an empty string (same as undefined)
out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ''})
- assert out.strip() == 'got:a.'
+ assert out.strip() == 'got:a.-1.'
assert 'toplevel' in err
assert 'mycat' not in err
assert 'foo 2 bar 3' not in err
@@ -306,7 +308,7 @@
assert 'bok' not in err
# check with PYPYLOG=:- (means print to stderr)
out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':-'})
- assert out.strip() == 'got:bcda.'
+ assert out.strip() == 'got:bcda.-1.'
assert 'toplevel' in err
assert '{mycat' in err
assert 'mycat}' in err
@@ -319,7 +321,8 @@
path = udir.join('test_debug_xxx.log')
out, err = cbuilder.cmdexec("", err=True,
env={'PYPYLOG': ':%s' % path})
- assert out.strip() == 'got:bcda.'
+ size = os.stat(str(path)).st_size
+ assert out.strip() == 'got:bcda.' + str(size) + '.'
assert not err
assert path.check(file=1)
data = path.read()
@@ -334,7 +337,8 @@
# check with PYPYLOG=somefilename
path = udir.join('test_debug_xxx_prof.log')
out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': str(path)})
- assert out.strip() == 'got:a.'
+ size = os.stat(str(path)).st_size
+ assert out.strip() == 'got:a.' + str(size) + '.'
assert not err
assert path.check(file=1)
data = path.read()
@@ -350,7 +354,8 @@
path = udir.join('test_debug_xxx_myc.log')
out, err = cbuilder.cmdexec("", err=True,
env={'PYPYLOG': 'myc:%s' % path})
- assert out.strip() == 'got:bda.'
+ size = os.stat(str(path)).st_size
+ assert out.strip() == 'got:bda.' + str(size) + '.'
assert not err
assert path.check(file=1)
data = path.read()
@@ -365,7 +370,8 @@
path = udir.join('test_debug_xxx_cat.log')
out, err = cbuilder.cmdexec("", err=True,
env={'PYPYLOG': 'cat:%s' % path})
- assert out.strip() == 'got:ca.'
+ size = os.stat(str(path)).st_size
+ assert out.strip() == 'got:ca.' + str(size) + '.'
assert not err
assert path.check(file=1)
data = path.read()
@@ -379,7 +385,8 @@
path = udir.join('test_debug_xxx_myc_cat2.log')
out, err = cbuilder.cmdexec("", err=True,
env={'PYPYLOG': 'myc,cat2:%s' % path})
- assert out.strip() == 'got:bcda.'
+ size = os.stat(str(path)).st_size
+ assert out.strip() == 'got:bcda.' + str(size) + '.'
assert not err
assert path.check(file=1)
data = path.read()
@@ -400,7 +407,7 @@
path = udir.join('test_debug_does_not_show_up.log')
out, err = cbuilder.cmdexec("", err=True,
env={'PYPYLOG': ':%s' % path})
- assert out.strip() == 'got:.'
+ assert out.strip() == 'got:.-1.'
assert not err
assert path.check(file=0)
@@ -682,6 +689,78 @@
out = cbuilder.cmdexec("")
assert out.strip() == "hi!"
+ def test_set_length_fraction(self):
+ # check for pypy.rlib.rstack._stack_set_length_fraction()
+ from pypy.rlib.rstack import _stack_set_length_fraction
+ from pypy.rlib.rstackovf import StackOverflow
+ class A:
+ n = 0
+ glob = A()
+ def f(n):
+ glob.n += 1
+ if n <= 0:
+ return 42
+ return f(n+1)
+ def entry_point(argv):
+ _stack_set_length_fraction(0.1)
+ try:
+ return f(1)
+ except StackOverflow:
+ glob.n = 0
+ _stack_set_length_fraction(float(argv[1]))
+ try:
+ return f(1)
+ except StackOverflow:
+ print glob.n
+ return 0
+ t, cbuilder = self.compile(entry_point, stackcheck=True)
+ counts = {}
+ for fraction in [0.1, 0.4, 1.0]:
+ out = cbuilder.cmdexec(str(fraction))
+ print 'counts[%s]: %r' % (fraction, out)
+ counts[fraction] = int(out.strip())
+ #
+ assert counts[1.0] >= 1000
+ # ^^^ should actually be much more than 1000 for this small test
+ assert counts[0.1] < counts[0.4] / 3
+ assert counts[0.4] < counts[1.0] / 2
+ assert counts[0.1] > counts[0.4] / 7
+ assert counts[0.4] > counts[1.0] / 4
+
+ def test_stack_criticalcode(self):
+ # check for pypy.rlib.rstack._stack_criticalcode_start/stop()
+ from pypy.rlib.rstack import _stack_criticalcode_start
+ from pypy.rlib.rstack import _stack_criticalcode_stop
+ from pypy.rlib.rstackovf import StackOverflow
+ class A:
+ pass
+ glob = A()
+ def f(n):
+ if n <= 0:
+ return 42
+ try:
+ return f(n+1)
+ except StackOverflow:
+ if glob.caught:
+ print 'Oups! already caught!'
+ glob.caught = True
+ _stack_criticalcode_start()
+ critical(100) # recurse another 100 times here
+ _stack_criticalcode_stop()
+ return 789
+ def critical(n):
+ if n > 0:
+ n = critical(n - 1)
+ return n - 42
+ def entry_point(argv):
+ glob.caught = False
+ print f(1)
+ return 0
+ t, cbuilder = self.compile(entry_point, stackcheck=True)
+ out = cbuilder.cmdexec('')
+ assert out.strip() == '789'
+
+
class TestMaemo(TestStandalone):
def setup_class(cls):
py.test.skip("TestMaemo: tests skipped for now")
diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py
--- a/pypy/translator/cli/opcodes.py
+++ b/pypy/translator/cli/opcodes.py
@@ -77,7 +77,6 @@
'cast_ptr_to_weakadr': [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF],
'gc__collect': 'call void class [mscorlib]System.GC::Collect()',
'gc_set_max_heap_size': Ignore,
- 'resume_point': Ignore,
'debug_assert': Ignore,
'debug_start_traceback': Ignore,
'debug_record_traceback': Ignore,
@@ -85,6 +84,8 @@
'debug_reraise_traceback': Ignore,
'debug_print_traceback': Ignore,
'debug_print': [DebugPrint],
+ 'debug_flush': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_FLUSH()'],
+ 'debug_offset': [PushAllArgs, 'call int32 [pypylib]pypy.runtime.DebugPrint::DEBUG_OFFSET()'],
'debug_start': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_START(string)'],
'debug_stop': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_STOP(string)'],
'have_debug_prints': [PushAllArgs, 'call bool [pypylib]pypy.runtime.DebugPrint::HAVE_DEBUG_PRINTS()'],
diff --git a/pypy/translator/cli/src/debug.cs b/pypy/translator/cli/src/debug.cs
--- a/pypy/translator/cli/src/debug.cs
+++ b/pypy/translator/cli/src/debug.cs
@@ -38,6 +38,20 @@
return false;
}
+ public static void DEBUG_FLUSH()
+ {
+ if (debug_file != null)
+ debug_file.Flush();
+ }
+
+ public static int DEBUG_OFFSET()
+ {
+ StreamWriter sw = debug_file as StreamWriter;
+ if (sw == null)
+ return -1;
+ return (int)sw.BaseStream.Position; // XXX: the cast might be incorrect
+ }
+
public static bool HAVE_DEBUG_PRINTS()
{
if ((have_debug_prints & 1) != 0) {
diff --git a/pypy/translator/goal/targetnumpystandalone.py b/pypy/translator/goal/targetnumpystandalone.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/goal/targetnumpystandalone.py
@@ -0,0 +1,57 @@
+
+""" Usage:
+
+./targetnumpystandalone-c <bytecode> array_size
+
+Will execute a give numpy bytecode. Arrays will be ranges (in float) modulo 10,
+constants would be consecutive starting from one.
+
+Bytecode should contain letters 'a' 'l' and 'f' so far and be correct
+"""
+
+import time
+from pypy.module.micronumpy.numarray import SingleDimArray, Code, compute
+from pypy.jit.codewriter.policy import JitPolicy
+
+def create_array(size):
+ a = SingleDimArray(size)
+ for i in range(size):
+ a.storage[i] = float(i % 10)
+ return a
+
+def entry_point(argv):
+ if len(argv) != 3:
+ print __doc__
+ return 1
+ bytecode = argv[1]
+ for b in bytecode:
+ if b not in 'alf':
+ print "WRONG BYTECODE"
+ print __doc__
+ return 2
+ try:
+ size = int(argv[2])
+ except ValueError:
+ print "INVALID LITERAL FOR INT:", argv[2]
+ print __doc__
+ return 3
+ no_arrays = bytecode.count('l')
+ no_floats = bytecode.count('f')
+ arrays = []
+ floats = []
+ for i in range(no_arrays):
+ arrays.append(create_array(size))
+ for i in range(no_floats):
+ floats.append(float(i + 1))
+ code = Code(bytecode, arrays, floats)
+ t0 = time.time()
+ compute(code)
+ print "bytecode:", bytecode, "size:", size
+ print "took:", time.time() - t0
+ return 0
+
+def target(*args):
+ return entry_point, None
+
+def jitpolicy(driver):
+ return JitPolicy()
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -105,7 +105,8 @@
return parser
def handle_config(self, config, translateconfig):
- if translateconfig._cfgimpl_value_owners['opt'] == 'default':
+ if (not translateconfig.help and
+ translateconfig._cfgimpl_value_owners['opt'] == 'default'):
raise Exception("You have to specify the --opt level.\n"
"Try --opt=2 or --opt=jit, or equivalently -O2 or -Ojit .")
self.translateconfig = translateconfig
diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py
--- a/pypy/translator/jvm/opcodes.py
+++ b/pypy/translator/jvm/opcodes.py
@@ -95,7 +95,6 @@
'gc__collect': jvm.SYSTEMGC,
'gc_set_max_heap_size': Ignore,
- 'resume_point': Ignore,
'jit_marker': Ignore,
'jit_force_virtualizable': Ignore,
'jit_force_virtual': DoNothing,
diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py
--- a/pypy/translator/oosupport/test_template/operations.py
+++ b/pypy/translator/oosupport/test_template/operations.py
@@ -107,12 +107,6 @@
return res
assert self.interpret(fn, [sys.maxint, 2]) == 1
- def test_ignore_resume_point(self):
- def fn(x):
- rstack.resume_point('hello world', x)
- return x
- assert self.interpret(fn, [42]) == 42
-
def test_rshift(self):
def fn(x, y):
return x >> y
diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py
--- a/pypy/translator/platform/posix.py
+++ b/pypy/translator/platform/posix.py
@@ -129,7 +129,9 @@
m.cfiles = rel_cfiles
rel_includedirs = [pypyrel(incldir) for incldir in
- self._preprocess_include_dirs(eci.include_dirs)]
+ self.preprocess_include_dirs(eci.include_dirs)]
+ rel_libdirs = [pypyrel(libdir) for libdir in
+ self.preprocess_library_dirs(eci.library_dirs)]
m.comment('automatically generated makefile')
definitions = [
@@ -139,7 +141,7 @@
('SOURCES', rel_cfiles),
('OBJECTS', rel_ofiles),
('LIBS', self._libs(eci.libraries)),
- ('LIBDIRS', self._libdirs(eci.library_dirs)),
+ ('LIBDIRS', self._libdirs(rel_libdirs)),
('INCLUDEDIRS', self._includedirs(rel_includedirs)),
('CFLAGS', cflags),
('CFLAGSEXTRA', list(eci.compile_extra)),
diff --git a/pypy/translator/platform/test/test_posix.py b/pypy/translator/platform/test/test_posix.py
--- a/pypy/translator/platform/test/test_posix.py
+++ b/pypy/translator/platform/test/test_posix.py
@@ -3,7 +3,7 @@
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.tool.udir import udir
from StringIO import StringIO
-import sys
+import sys, os
def test_echo():
res = host.execute('echo', '42 24')
@@ -49,6 +49,19 @@
mk.write()
assert 'LINKFILES = /foo/bar.a' in tmpdir.join('Makefile').read()
+ def test_preprocess_localbase(self):
+ tmpdir = udir.join('test_preprocess_localbase').ensure(dir=1)
+ eci = ExternalCompilationInfo()
+ os.environ['PYPY_LOCALBASE'] = '/foo/baz'
+ try:
+ mk = self.platform.gen_makefile(['blip.c'], eci, path=tmpdir)
+ mk.write()
+ finally:
+ del os.environ['PYPY_LOCALBASE']
+ Makefile = tmpdir.join('Makefile').read()
+ assert 'INCLUDEDIRS = -I/foo/baz/include' in Makefile
+ assert 'LIBDIRS = -L/foo/baz/lib' in Makefile
+
class TestMaemo(TestMakefile):
strict_on_stderr = False
diff --git a/pypy/translator/stackless/frame.py b/pypy/translator/stackless/frame.py
--- a/pypy/translator/stackless/frame.py
+++ b/pypy/translator/stackless/frame.py
@@ -104,10 +104,8 @@
class RestartInfo(object):
- """A RestartInfo is created (briefly) for each graph that contains
- a resume point.
-
- In addition, a RestartInfo is created for each function that needs
+ """
+ A RestartInfo is created for each function that needs
to do explicit stackless manipulations
(e.g. code.yield_current_frame_to_caller)."""
diff --git a/pypy/translator/stackless/test/test_coroutine_reconstruction.py b/pypy/translator/stackless/test/test_coroutine_reconstruction.py
deleted file mode 100644
--- a/pypy/translator/stackless/test/test_coroutine_reconstruction.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from pypy.rlib import rcoroutine
-from pypy.rlib import rstack
-from pypy.rlib.rstack import resume_state_create
-from pypy.translator.stackless.test.test_transform import llinterp_stackless_function
-from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.lltypesystem import lltype
-
-namespace = rcoroutine.make_coroutine_classes(object)
-syncstate = namespace['syncstate']
-AbstractThunk = namespace['AbstractThunk']
-Coroutine = namespace['Coroutine']
-
-class TestCoroutineReconstruction:
-
- def setup_meth(self):
- syncstate.reset()
-
- def test_simple_ish(self):
-
- output = []
- def f(coro, n, x):
- if n == 0:
- coro.switch()
- rstack.resume_point("f_0")
- assert rstack.stack_frames_depth() == 9
- return
- f(coro, n-1, 2*x)
- rstack.resume_point("f_1", coro, n, x)
- output.append(x)
-
- class T(AbstractThunk):
- def __init__(self, arg_coro, arg_n, arg_x):
- self.arg_coro = arg_coro
- self.arg_n = arg_n
- self.arg_x = arg_x
- def call(self):
- f(self.arg_coro, self.arg_n, self.arg_x)
-
- def example():
- main_coro = Coroutine.getcurrent()
- sub_coro = Coroutine()
- thunk_f = T(main_coro, 5, 1)
- sub_coro.bind(thunk_f)
- sub_coro.switch()
-
- new_coro = Coroutine()
- new_thunk_f = T(main_coro, 5, 1)
- new_coro.bind(new_thunk_f)
-
- costate = Coroutine._get_default_costate()
- bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
- _bind_frame = resume_state_create(bottom, "coroutine__bind", costate)
- f_frame_1 = resume_state_create(_bind_frame, "f_1", main_coro, 5, 1)
- f_frame_2 = resume_state_create(f_frame_1, "f_1", main_coro, 4, 2)
- f_frame_3 = resume_state_create(f_frame_2, "f_1", main_coro, 3, 4)
- f_frame_4 = resume_state_create(f_frame_3, "f_1", main_coro, 2, 8)
- f_frame_5 = resume_state_create(f_frame_4, "f_1", main_coro, 1, 16)
- f_frame_0 = resume_state_create(f_frame_5, "f_0")
- switch_frame = resume_state_create(f_frame_0, "coroutine_switch", costate)
-
- new_coro.frame = switch_frame
-
- new_coro.switch()
- return output == [16, 8, 4, 2, 1]
-
- res = llinterp_stackless_function(example)
- assert res == 1
-
diff --git a/pypy/translator/stackless/test/test_resume_point.py b/pypy/translator/stackless/test/test_resume_point.py
deleted file mode 100644
--- a/pypy/translator/stackless/test/test_resume_point.py
+++ /dev/null
@@ -1,457 +0,0 @@
-from pypy.translator.stackless.transform import StacklessTransformer
-from pypy.translator.stackless.test.test_transform import llinterp_stackless_function, rtype_stackless_function, one, run_stackless_function
-from pypy import conftest
-import py
-from pypy.rlib import rstack
-
-def do_backendopt(t):
- from pypy.translator.backendopt import all
- all.backend_optimizations(t)
-
-def transform_stackless_function(fn, callback_for_transform=None):
- def wrapper(argv):
- return fn()
- t = rtype_stackless_function(wrapper)
- if callback_for_transform:
- callback_for_transform(t)
- if conftest.option.view:
- t.view()
- st = StacklessTransformer(t, wrapper, False)
- st.transform_all()
-
-def test_no_call():
- def f(x, y):
- x = x-1
- rstack.resume_point("rp0", x, y)
- r = x+y
- rstack.stack_unwind()
- return r
- def example():
- v1 = f(one(),one()+one())
- state = rstack.resume_state_create(None, "rp0", one(), one()+one()+one())
- v2 = rstack.resume_state_invoke(int, state)
- return v1*10 + v2
-## transform_stackless_function(example)
- res = llinterp_stackless_function(example, assert_unwind=False)
- assert res == 24
-
-def test_bogus_restart_state_create():
- def f(x, y):
- x = x-1
- rstack.resume_point("rp0", x, y)
- return x+y
- def example():
- v1 = f(one(),one()+one())
- state = rstack.resume_state_create(None, "rp0", one())
- return v1
- info = py.test.raises(AssertionError, "transform_stackless_function(example)")
- assert 'rp0' in str(info.value)
-
-
-def test_call():
- def g(x,y):
- return x*y
- def f(x, y):
- z = g(x,y)
- rstack.resume_point("rp1", y, returns=z)
- return z+y
- def example():
- v1 = f(one(),one()+one())
- s = rstack.resume_state_create(None, "rp1", 5*one())
- v2 = rstack.resume_state_invoke(int, s, returning=one()*7)
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 412
- res = run_stackless_function(example)
- assert res == 412
-
-def test_returns_with_instance():
- class C:
- def __init__(self, x):
- self.x = x
- def g(x):
- return C(x+1)
- def f(x, y):
- r = g(x)
- rstack.resume_point("rp1", y, returns=r)
- return r.x + y
- def example():
- v1 = f(one(),one()+one())
- s = rstack.resume_state_create(None, "rp1", 5*one())
- v2 = rstack.resume_state_invoke(int, s, returning=C(one()*3))
- return v1*100 + v2
- res = llinterp_stackless_function(example, assert_unwind=False)
- assert res == 408
- res = run_stackless_function(example)
- assert res == 408
-
-def test_call_uncovered():
- def g(x,y):
- return x*y
- def f(x, y):
- z = g(x,y)
- rstack.resume_point("rp1", y, returns=z)
- return z+y+x
- def example():
- f(one(),one()+one())
- return 0
- e = py.test.raises(Exception, transform_stackless_function, example)
- msg, = e.value.args
- assert msg.startswith('not covered needed value at resume_point') and 'rp1' in msg
-
-def test_chained_states():
- def g(x, y):
- x += 1
- rstack.resume_point("rp1", x, y)
- return x + y
- def f(x, y, z):
- y += 1
- r = g(x, y)
- rstack.resume_point("rp2", z, returns=r)
- return r + z
- def example():
- v1 = f(one(), 2*one(), 3*one())
- s2 = rstack.resume_state_create(None, "rp2", 2*one())
- s1 = rstack.resume_state_create(s2, "rp1", 4*one(), 5*one())
- return 100*v1 + rstack.resume_state_invoke(int, s1)
- res = llinterp_stackless_function(example)
- assert res == 811
- res = run_stackless_function(example)
- assert res == 811
-
-def test_return_instance():
- class C:
- pass
- def g(x):
- c = C()
- c.x = x + 1
- rstack.resume_point("rp1", c)
- return c
- def f(x, y):
- r = g(x)
- rstack.resume_point("rp2", y, returns=r)
- return r.x + y
- def example():
- v1 = f(one(), 2*one())
- s2 = rstack.resume_state_create(None, "rp2", 2*one())
- c = C()
- c.x = 4*one()
- s1 = rstack.resume_state_create(s2, "rp1", c)
- return v1*100 + rstack.resume_state_invoke(int, s1)
- res = llinterp_stackless_function(example)
- assert res == 406
- res = run_stackless_function(example)
- assert res == 406
-
-def test_really_return_instance():
- class C:
- pass
- def g(x):
- c = C()
- c.x = x + 1
- rstack.resume_point("rp1", c)
- return c
- def example():
- v1 = g(one()).x
- c = C()
- c.x = 4*one()
- s1 = rstack.resume_state_create(None, "rp1", c)
- return v1*100 + rstack.resume_state_invoke(C, s1).x
- res = llinterp_stackless_function(example)
- assert res == 204
- res = run_stackless_function(example)
- assert res == 204
-
-def test_resume_and_raise():
- def g(x):
- rstack.resume_point("rp0", x)
- if x == 0:
- raise KeyError
- return x + 1
- def example():
- v1 = g(one())
- s = rstack.resume_state_create(None, "rp0", one()-1)
- try:
- v2 = rstack.resume_state_invoke(int, s)
- except KeyError:
- v2 = 42
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 242
- res = run_stackless_function(example)
- assert res == 242
-
-def test_resume_and_raise_and_catch():
- def g(x):
- rstack.resume_point("rp0", x)
- if x == 0:
- raise KeyError
- return x + 1
- def f(x):
- x = x - 1
- try:
- r = g(x)
- rstack.resume_point("rp1", returns=r)
- except KeyError:
- r = 42
- return r - 1
- def example():
- v1 = f(one()+one())
- s1 = rstack.resume_state_create(None, "rp1")
- s0 = rstack.resume_state_create(s1, "rp0", one()-1)
- v2 = rstack.resume_state_invoke(int, s0)
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 141
- res = run_stackless_function(example)
- assert res == 141
-
-def test_invoke_raising():
- def g(x):
- rstack.resume_point("rp0", x)
- return x + 1
- def f(x):
- x = x - 1
- try:
- r = g(x)
- rstack.resume_point("rp1", returns=r)
- except KeyError:
- r = 42
- return r - 1
- def example():
- v1 = f(one()+one())
- s1 = rstack.resume_state_create(None, "rp1")
- s0 = rstack.resume_state_create(s1, "rp0", 0)
- v2 = rstack.resume_state_invoke(int, s0, raising=KeyError())
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 141
- res = run_stackless_function(example)
- assert res == 141
-
-
-def test_finally():
- def f(x):
- rstack.resume_point("rp1", x)
- return 1/x
- def in_finally(x):
- rstack.resume_point("rp1.5", x)
- return 2/x
- def g(x):
- r = y = 0
- r += f(x)
- try:
- y = f(x)
- rstack.resume_point("rp0", x, r, returns=y)
- finally:
- r += in_finally(x)
- return r + y
- def example():
- return g(one())
- transform_stackless_function(example)
-
-def test_except():
- py.test.skip("please don't write code like this")
- def f(x):
- rstack.resume_point("rp1", x)
- return 1/x
- def g(x):
- r = y = 0
- r += f(x)
- try:
- y = f(x)
- rstack.resume_point("rp0", x, r, y, returns=y)
- except ZeroDivisionError:
- r += f(x)
- return r + y
- def example():
- return g(one())
- transform_stackless_function(example)
-
-def test_using_pointers():
- from pypy.interpreter.miscutils import FixedStack
- class Arguments:
- def __init__(self, a, b, c, d, e):
- pass
- class W_Root:
- pass
- class FakeFrame:
- def __init__(self, space):
- self.space = space
- self.valuestack = FixedStack()
- self.valuestack.setup(10)
- self.valuestack.push(W_Root())
- class FakeSpace:
- def call_args(self, args, kw):
- return W_Root()
- def str_w(self, ob):
- return 'a string'
- def call_function(f, oparg, w_star=None, w_starstar=None):
- n_arguments = oparg & 0xff
- n_keywords = (oparg>>8) & 0xff
- keywords = None
- if n_keywords:
- keywords = {}
- for i in range(n_keywords):
- w_value = f.valuestack.pop()
- w_key = f.valuestack.pop()
- key = f.space.str_w(w_key)
- keywords[key] = w_value
- arguments = [None] * n_arguments
- for i in range(n_arguments - 1, -1, -1):
- arguments[i] = f.valuestack.pop()
- args = Arguments(f.space, arguments, keywords, w_star, w_starstar)
- w_function = f.valuestack.pop()
- w_result = f.space.call_args(w_function, args)
- rstack.resume_point("call_function", f, returns=w_result)
- f.valuestack.push(w_result)
- def example():
- s = FakeSpace()
- f = FakeFrame(s)
- call_function(f, 100, W_Root(), W_Root())
- return one()
- transform_stackless_function(example, do_backendopt)
-
-def test_always_raising():
- def g(out):
- out.append(3)
- rstack.resume_point('g')
- raise KeyError
-
- def h(out):
- try:
- # g is always raising, good enough to put the resume point
- # before, instead of after!
- rstack.resume_point('h', out)
- g(out)
- except KeyError:
- return 0
- return -1
-
- def example():
- out = []
- x = h(out)
- l = len(out)
- chain = rstack.resume_state_create(None, 'h', out)
- chain = rstack.resume_state_create(chain, 'g')
- x += rstack.resume_state_invoke(int, chain)
- l += len(out)
- return l*100+x
-
- res = llinterp_stackless_function(example)
- assert res == 200
- res = run_stackless_function(example)
- assert res == 200
-
-def test_more_mess():
- from pypy.interpreter.miscutils import Stack
-
- def new_framestack():
- return Stack()
-
- class FakeFrame:
- pass
- class FakeSlpFrame:
- def switch(self):
- rstack.stack_unwind()
- return FakeSlpFrame()
-
- class FakeCoState:
- def update(self, new):
- self.last, self.current = self.current, new
- frame, new.frame = new.frame, None
- return frame
- def do_things_to_do(self):
- self.do_things_to_do()
-
- costate = FakeCoState()
- costate.current = None
-
- class FakeExecutionContext:
- def __init__(self):
- self.space = space
- self.framestack = new_framestack()
-
- def subcontext_new(coobj):
- coobj.framestack = new_framestack()
- subcontext_new = staticmethod(subcontext_new)
-
- def subcontext_enter(self, next):
- self.framestack = next.framestack
-
- def subcontext_leave(self, current):
- current.framestack = self.framestack
-
- class FakeSpace:
- def __init__(self):
- self.ec = None
- def getexecutioncontext(self):
- if self.ec is None:
- self.ec = FakeExecutionContext()
- return self.ec
-
- space = FakeSpace()
-
- class MainCoroutineGetter(object):
- def __init__(self):
- self.costate = None
- def _get_default_costate(self):
- if self.costate is None:
- costate = FakeCoState()
- self.costate = costate
- return costate
- return self.costate
-
- main_coroutine_getter = MainCoroutineGetter()
-
- class FakeCoroutine:
- def __init__(self):
- self.frame = None
- self.costate = costate
- space.getexecutioncontext().subcontext_new(self)
-
- def switch(self):
- if self.frame is None:
- raise RuntimeError
- state = self.costate
- incoming_frame = state.update(self).switch()
- rstack.resume_point("coroutine_switch", self, state, returns=incoming_frame)
- left = state.last
- left.frame = incoming_frame
- left.goodbye()
- self.hello()
- #main_coroutine_getter._get_default_costate().do_things_to_do()
-
- def hello(self):
- pass
-
- def goodbye(self):
- pass
-
- class FakeAppCoroutine(FakeCoroutine):
- def __init__(self):
- FakeCoroutine.__init__(self)
- self.space = space
-
- def hello(self):
- ec = self.space.getexecutioncontext()
- ec.subcontext_enter(self)
-
- def goodbye(self):
- ec = self.space.getexecutioncontext()
- ec.subcontext_leave(self)
-
- def example():
- coro = FakeAppCoroutine()
- othercoro = FakeCoroutine()
- othercoro.frame = FakeSlpFrame()
- if one():
- coro.frame = FakeSlpFrame()
- if one() - one():
- coro.costate = FakeCoState()
- coro.costate.last = coro.costate.current = othercoro
- space.getexecutioncontext().framestack.push(FakeFrame())
- coro.switch()
- return one()
-
- transform_stackless_function(example, do_backendopt)
diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py
--- a/pypy/translator/stackless/transform.py
+++ b/pypy/translator/stackless/transform.py
@@ -112,19 +112,6 @@
# abort()
# return retval + x + 1
-class SymbolicRestartNumber(ComputedIntSymbolic):
- def __init__(self, label, value=None):
- ComputedIntSymbolic.__init__(self, self._getvalue)
- self.label = label
- self.value = value
-
- def _getvalue(self):
- # argh, we'd like to assert-fail if value is None here, but we
- # get called too early (during databasing) for this to be
- # valid. so we might return None and rely on the database
- # checking that this only happens before the database is
- # complete.
- return self.value
# the strategy for sharing parts of the resume code:
#
@@ -248,8 +235,7 @@
self.stackless_gc = stackless_gc
def analyze_simple_operation(self, op, graphinfo):
- if op.opname in ('yield_current_frame_to_caller', 'resume_point',
- 'resume_state_invoke', 'resume_state_create', 'stack_frames_depth',
+ if op.opname in ('yield_current_frame_to_caller', 'stack_frames_depth',
'stack_switch', 'stack_unwind', 'stack_capture',
'get_stack_depth_limit', 'set_stack_depth_limit'):
return True
@@ -458,24 +444,11 @@
self.is_finished = False
- # only for sanity checking, but still very very important
- self.explicit_resume_point_data = {}
-
- self.symbolic_restart_numbers = {}
-
- # register the prebuilt restartinfos & give them names for use
- # with resume_state_create
# the mauling of frame_typer internals should be a method on FrameTyper.
for restartinfo in frame.RestartInfo.prebuilt:
name = restartinfo.func_or_graph.__name__
for i in range(len(restartinfo.frame_types)):
- label = name + '_' + str(i)
- assert label not in self.symbolic_restart_numbers
- # XXX we think this is right:
- self.symbolic_restart_numbers[label] = SymbolicRestartNumber(
- label, len(self.masterarray1) + i)
frame_type = restartinfo.frame_types[i]
- self.explicit_resume_point_data[label] = frame_type
self.frametyper.ensure_frame_type_for_types(frame_type)
self.register_restart_info(restartinfo)
@@ -589,156 +562,6 @@
# yes
convertblock.exits[0].args[index] = newvar
# end ouch!
-
- def handle_resume_point(self, block, i):
- # in some circumstances we might be able to reuse
- # an already inserted resume point
- op = block.operations[i]
- if i == len(block.operations) - 1:
- link = block.exits[0]
- nextblock = None
- else:
- link = split_block(None, block, i+1)
- i = 0
- nextblock = link.target
-
- label = op.args[0].value
-
- parms = op.args[1:]
- if not isinstance(parms[0], model.Variable):
- assert parms[0].value is None
- parms[0] = None
- args = vars_to_save(block)
- for a in args:
- if a not in parms:
- raise Exception, "not covered needed value at resume_point %r"%(label,)
- if parms[0] is not None: # returns= case
- res = parms[0]
- args = [arg for arg in args if arg is not res]
- else:
- args = args
- res = op.result
-
- (FRAME_TYPE, varsforcall, saver) = self.frametyper.frame_type_for_vars(parms[1:])
-
- if label in self.explicit_resume_point_data:
- OTHER_TYPE = self.explicit_resume_point_data[label]
- assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,)
- else:
- self.explicit_resume_point_data[label] = FRAME_TYPE
-
- self._make_resume_handling(FRAME_TYPE, varsforcall, res, block.exits)
-
- restart_number = len(self.masterarray1) + len(self.resume_blocks) - 1
-
- if label in self.symbolic_restart_numbers:
- symb = self.symbolic_restart_numbers[label]
- assert symb.value is None
- symb.value = restart_number
- else:
- symb = SymbolicRestartNumber(label, restart_number)
- self.symbolic_restart_numbers[label] = symb
-
- return nextblock
-
- def handle_resume_state_create(self, block, i):
- op = block.operations[i]
- llops = LowLevelOpList()
- label = op.args[1].value
- parms = op.args[2:]
- FRAME_TYPE, varsforcall, saver = self.frametyper.frame_type_for_vars(parms)
-
- if label in self.explicit_resume_point_data:
- OTHER_TYPE = self.explicit_resume_point_data[label]
- assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,)
- else:
- self.explicit_resume_point_data[label] = FRAME_TYPE
-
- if label in self.symbolic_restart_numbers:
- symb = self.symbolic_restart_numbers[label]
- else:
- symb = SymbolicRestartNumber(label)
- self.symbolic_restart_numbers[label] = symb
-
- # this is rather insane: we create an exception object, pass
- # it to the saving function, then read the thus created state
- # out of and then clear global_state.top
- c_EXC = model.Constant(self.unwind_exception_type.TO, lltype.Void)
- c_flags = model.Constant({'flavor': 'gc'}, lltype.Void)
- v_exc = llops.genop('malloc', [c_EXC, c_flags],
- resulttype = self.unwind_exception_type)
- llops.genop('setfield', [v_exc,
- model.Constant('inst_depth', lltype.Void),
- model.Constant(0, lltype.Signed)])
-
- realvarsforcall = []
- for v in varsforcall:
- if v.concretetype != lltype.Void:
- realvarsforcall.append(gen_cast(llops, storage_type(v.concretetype), v))
-
- llops.genop('direct_call',
- [model.Constant(saver, lltype.typeOf(saver)), v_exc,
- model.Constant(symb, lltype.Signed)] + realvarsforcall,
- resulttype = lltype.Void)
- v_state = varoftype(lltype.Ptr(frame.STATE_HEADER))
- v_state_hdr = llops.genop("getfield",
- [self.ll_global_state, self.c_inst_top_name],
- resulttype=lltype.Ptr(STATE_HEADER))
- v_state = gen_cast(llops, lltype.Ptr(FRAME_TYPE), v_state_hdr)
- llops.genop("setfield",
- [self.ll_global_state, self.c_inst_top_name, self.c_null_state])
-
- v_prevstate = gen_cast(llops, lltype.Ptr(frame.STATE_HEADER), op.args[0])
- llops.genop('direct_call', [self.set_back_pointer_ptr,
- v_state_hdr, v_prevstate])
- llops.append(model.SpaceOperation('cast_opaque_ptr', [v_state_hdr], op.result))
- block.operations[i:i+1] = llops
-
- def handle_resume_state_invoke(self, block):
- op = block.operations[-1]
- assert op.opname == 'resume_state_invoke'
- # some commentary.
- #
- # we don't want to write 155 or so different versions of
- # resume_after_foo that appear to the annotator to return
- # different types. we take advantage of the fact that this
- # function always raises UnwindException and have it (appear
- # to) return Void. then to placate all the other machinery,
- # we pass a constant zero-of-the-appropriate-type along the
- # non-exceptional link (which we know will never be taken).
- # Nota Bene: only mutate a COPY of the non-exceptional link
- # because the non-exceptional link has been stored in
- # self.resume_blocks and we don't want a constant "zero" in
- # there.
- v_state = op.args[0]
- v_returning = op.args[1]
- v_raising = op.args[2]
- llops = LowLevelOpList()
-
- if v_raising.concretetype == lltype.Void:
- erased_type = storage_type(v_returning.concretetype)
- resume_after_ptr = self.resume_afters[erased_type]
- v_param = v_returning
- else:
- assert v_returning.concretetype == lltype.Void
- erased_type = self.exception_type
- resume_after_ptr = self.resume_after_raising_ptr
- v_param = v_raising
-
- if erased_type != v_param.concretetype:
- v_param = gen_cast(llops, erased_type, v_param)
- llops.genop('direct_call', [resume_after_ptr, v_state, v_param],
- resulttype=lltype.Void)
-
- del block.operations[-1]
- block.operations.extend(llops)
-
- noexclink = block.exits[0].copy()
- realrettype = op.result.concretetype
- for i, a in enumerate(noexclink.args):
- if a is op.result:
- noexclink.args[i] = model.Constant(realrettype._defl(), realrettype)
- block.recloseblock(*((noexclink,) + block.exits[1:]))
def insert_unwind_handling(self, block, i):
# for the case where we are resuming to an except:
@@ -821,19 +644,8 @@
op = replace_with_call(self.operation_replacement[op.opname])
stackless_op = True
- if op.opname == 'resume_state_create':
- self.handle_resume_state_create(block, i)
- continue # go back and look at that malloc
-
if (op.opname in ('direct_call', 'indirect_call')
or self.analyzer.analyze(op)):
- if op.opname == 'resume_point':
- block = self.handle_resume_point(block, i)
- if block is None:
- return
- else:
- i = 0
- continue
if not stackless_op and not self.analyzer.analyze(op):
i += 1
@@ -849,9 +661,7 @@
continue
nextblock = self.insert_unwind_handling(block, i)
- if op.opname == 'resume_state_invoke':
- self.handle_resume_state_invoke(block)
-
+
if nextblock is None:
return
diff --git a/pypy/translator/transform.py b/pypy/translator/transform.py
--- a/pypy/translator/transform.py
+++ b/pypy/translator/transform.py
@@ -175,41 +175,6 @@
# make sure the bookkeeper knows about AssertionError
self.bookkeeper.getuniqueclassdef(AssertionError)
-def insert_stackcheck(ann):
- from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles
- edges = []
- graphs_to_patch = {}
- for callposition, (caller, callee) in ann.translator.callgraph.items():
- if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False):
- graphs_to_patch[callee] = True
- continue
- edge = Edge(caller, callee)
- edge.callposition = callposition
- edges.append(edge)
-
- for graph in graphs_to_patch:
- v = Variable()
- ann.setbinding(v, annmodel.SomeImpossibleValue())
- unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
- graph.startblock.operations.insert(0, unwind_op)
-
- edgedict = make_edge_dict(edges)
- for edge in break_cycles(edgedict, edgedict):
- caller = edge.source
- _, _, call_tag = edge.callposition
- if call_tag:
- caller_block, _ = call_tag
- else:
- ann.warning("cycle detected but no information on where to insert "
- "stack_check()")
- continue
- # caller block found, insert stack_check()
- v = Variable()
- # push annotation on v
- ann.setbinding(v, annmodel.SomeImpossibleValue())
- unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
- caller_block.operations.insert(0, unwind_op)
-
def insert_ll_stackcheck(translator):
from pypy.translator.backendopt.support import find_calls_from
from pypy.rlib.rstack import stack_check
More information about the pypy-commit
mailing list