1. trampgeek
  2. pypy-sandbox-4-pycode

Commits

Carl Friedrich Bolz  committed 074aae0 Merge

merge default

  • Participants
  • Parent commits 617ce44, 03ac38e
  • Branches set-strategies

Comments (0)

Files changed (164)

File .hgtags

View file
  • Ignore whitespace
 b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5
 b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked
 d8ac7d23d3ec5f9a0fa1264972f74a010dbfd07f release-1.6
+ff4af8f318821f7f5ca998613a60fca09aa137da release-1.7

File lib_pypy/_sqlite3.py

View file
  • Ignore whitespace
 sqlite.sqlite3_result_text.argtypes = [c_void_p, c_char_p, c_int, c_void_p]
 sqlite.sqlite3_result_text.restype = None
 
+sqlite.sqlite3_enable_load_extension.argtypes = [c_void_p, c_int]
+sqlite.sqlite3_enable_load_extension.restype = c_int
+
 ##########################################
 # END Wrapped SQLite C API and constants
 ##########################################
         from sqlite3.dump import _iterdump
         return _iterdump(self)
 
+    def enable_load_extension(self, enabled):
+        self._check_thread()
+        self._check_closed()
+
+        rc = sqlite.sqlite3_enable_load_extension(self.db, int(enabled))
+        if rc != SQLITE_OK:
+            raise OperationalError("Error enabling load extension")
+
 DML, DQL, DDL = range(3)
 
 class Cursor(object):

File lib_pypy/pyrepl/unix_console.py

View file
  • Ignore whitespace
                    e.args[4] == 'unexpected end of data':
                 pass
             else:
-                raise
+                # was: "raise".  But it crashes pyrepl, and by extension the
+                # pypy currently running, in which we are e.g. in the middle
+                # of some debugging session.  Argh.  Instead just print an
+                # error message to stderr and continue running, for now.
+                self.partial_char = ''
+                sys.stderr.write('\n%s: %s\n' % (e.__class__.__name__, e))
         else:
             self.partial_char = ''
             self.event_queue.push(c)

File lib_pypy/syslog.py

View file
  • Ignore whitespace
 _setlogmask.argtypes = (c_int,)
 _setlogmask.restype = c_int
 
+_S_log_open = False
+_S_ident_o = None
+
+def _get_argv():
+    try:
+        import sys
+        script = sys.argv[0]
+        if isinstance(script, str):
+            return script[script.rfind('/')+1:] or None
+    except Exception:
+        pass
+    return None
+
 @builtinify
-def openlog(ident, option, facility):
-    _openlog(ident, option, facility)
+def openlog(ident=None, logoption=0, facility=LOG_USER):
+    global _S_ident_o, _S_log_open
+    if ident is None:
+        ident = _get_argv()
+    _S_ident_o = c_char_p(ident)    # keepalive
+    _openlog(_S_ident_o, logoption, facility)
+    _S_log_open = True
 
 @builtinify
 def syslog(arg1, arg2=None):
         priority, message = arg1, arg2
     else:
         priority, message = LOG_INFO, arg1
+    # if log is not opened, open it now
+    if not _S_log_open:
+        openlog()
     _syslog(priority, "%s", message)
 
 @builtinify
 def closelog():
-    _closelog()
+    global _S_log_open, S_ident_o
+    if _S_log_open:
+        _closelog()
+        _S_log_open = False
+        _S_ident_o = None
 
 @builtinify
 def setlogmask(mask):

File pypy/config/pypyoption.py

View file
  • Ignore whitespace
                    "actually create the full list until the resulting "
                    "list is mutated",
                    default=False),
+        BoolOption("withliststrategies",
+                   "enable optimized ways to store lists of primitives ",
+                   default=True),
 
         BoolOption("withtypeversion",
                    "version type objects when changing them",

File pypy/config/test/test_translationoption.py

View file
  • Ignore whitespace
+import py
+from pypy.config.translationoption import get_combined_translation_config
+from pypy.config.translationoption import set_opt_level
+from pypy.config.config import ConflictConfigError
+
+
+def test_no_gcrootfinder_with_boehm():
+    config = get_combined_translation_config()
+    config.translation.gcrootfinder = "shadowstack"
+    py.test.raises(ConflictConfigError, set_opt_level, config, '0')

File pypy/config/translationoption.py

View file
  • Ignore whitespace
     # make_sure_not_resized often relies on it, so we always enable them
     config.translation.suggest(list_comprehension_operations=True)
 
+    # finally, make the choice of the gc definitive.  This will fail
+    # if we have specified strange inconsistent settings.
+    config.translation.gc = config.translation.gc
+
 # ----------------------------------------------------------------
 
 def set_platform(config):

File pypy/doc/coding-guide.rst

View file
  • Ignore whitespace
   - *slicing*:
     the slice start must be within bounds. The stop doesn't need to, but it must
     not be smaller than the start.  All negative indexes are disallowed, except for
-    the [:-1] special case.  No step.
+    the [:-1] special case.  No step.  Slice deletion follows the same rules.
+    
+  - *slice assignment*:
+    only supports ``lst[x:y] = sublist``, if ``len(sublist) == y - x``.
+    In other words, slice assignment cannot change the total length of the list,
+    but just replace items.
 
   - *other operators*:
     ``+``, ``+=``, ``in``, ``*``, ``*=``, ``==``, ``!=`` work as expected.

File pypy/doc/config/objspace.std.withliststrategies.txt

View file
  • Ignore whitespace
+Enable list strategies: Use specialized representations for lists of primitive
+objects, such as ints.

File pypy/doc/cpython_differences.rst

View file
  • Ignore whitespace
 documented as such (as e.g. for hasattr()), in most cases PyPy
 lets the exception propagate instead.
 
+Object Identity of Primitive Values, ``is`` and ``id``
+-------------------------------------------------------
+
+Object identity of primitive values works by value equality, not by identity of
+the wrapper. This means that ``x + 1 is x + 1`` is always true, for arbitrary
+integers ``x``. The rule applies for the following types:
+
+ - ``int``
+
+ - ``float``
+
+ - ``long``
+
+ - ``complex``
+
+This change requires some changes to ``id`` as well. ``id`` fulfills the
+following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
+above types will return a value that is computed from the argument, and can
+thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long).
+
 
 Miscellaneous
 -------------
   never a dictionary as it sometimes is in CPython. Assigning to
   ``__builtins__`` has no effect.
 
-* Do not compare immutable objects with ``is``.  For example on CPython
-  it is true that ``x is 0`` works, i.e. does the same as ``type(x) is
-  int and x == 0``, but it is so by accident.  If you do instead
-  ``x is 1000``, then it stops working, because 1000 is too large and
-  doesn't come from the internal cache.  In PyPy it fails to work in
-  both cases, because we have no need for a cache at all.
-
-* Also, object identity of immutable keys in dictionaries is not necessarily
-  preserved.
 
 .. include:: _ref.txt

File pypy/doc/how-to-release.rst

View file
  • Ignore whitespace
-.. include:: needswork.txt
-
-.. needs work, it talks about svn. also, it is not really user documentation
 
 Making a PyPy Release
 =======================
 forgetting things. A set of todo files may also work.
 
 Check and prioritize all issues for the release, postpone some if necessary,
-create new  issues also as necessary. A meeting (or meetings) should be
-organized to decide what things are priorities, should go in and work for
-the release. 
-
-An important thing is to get the documentation into an up-to-date state!
+create new  issues also as necessary. An important thing is to get
+the documentation into an up-to-date state!
 
 Release Steps
 ----------------

File pypy/doc/project-ideas.rst

View file
  • Ignore whitespace
 PyPy's implementation of the Python ``long`` type is slower than CPython's.
 Find out why and optimize them.
 
+Make bytearray type fast
+------------------------
+
+PyPy's bytearray type is very inefficient. It would be an interesting
+task to look into possible optimizations on this.
+
 Numpy improvements
 ------------------
 
-This is more of a project-container than a single project. Possible ideas:
+The numpy is rapidly progressing in pypy, so feel free to come to IRC and
+ask for proposed topic. A not necesarilly up-to-date `list of topics`_
+is also available.
 
-* 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.
+.. _`list of topics`: https://bitbucket.org/pypy/extradoc/src/extradoc/planning/micronumpy.txt
 
 Improving the jitviewer
 ------------------------

File pypy/doc/release-1.7.0.rst

View file
  • Ignore whitespace
+==================================
+PyPy 1.7 - widening the sweet spot
+==================================
+
+We're pleased to announce the 1.7 release of PyPy. As became a habit, this
+release brings a lot of bugfixes and performance improvements over the 1.6
+release. However, unlike the previous releases, the focus has been on widening
+the "sweet spot" of PyPy. That is, classes of Python code that PyPy can greatly
+speed up should be vastly improved with this release. You can download the 1.7
+release here:
+
+    http://pypy.org/download.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 1.7 and cpython 2.7.1`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 32/64 or
+Windows 32. Windows 64 work is ongoing, but not yet natively supported.
+
+The main topic of this release is widening the range of code which PyPy
+can greatly speed up. On average on
+our benchmark suite, PyPy 1.7 is around **30%** faster than PyPy 1.6 and up
+to **20 times** faster on some benchmarks.
+
+.. _`pypy 1.7 and cpython 2.7.1`: http://speed.pypy.org
+
+
+Highlights
+==========
+
+* Numerous performance improvements. There are too many examples which python
+  constructs now should behave faster to list them.
+
+* Bugfixes and compatibility fixes with CPython.
+
+* Windows fixes.
+
+* PyPy now comes with stackless features enabled by default. However,
+  any loop using stackless features will interrupt the JIT for now, so no real
+  performance improvement for stackless-based programs. Contact pypy-dev for
+  info how to help on removing this restriction.
+
+* NumPy effort in PyPy was renamed numpypy. In order to try using it, simply
+  write::
+
+    import numpypy as numpy
+
+  at the beginning of your program. There is a huge progress on numpy in PyPy
+  since 1.6, the main feature being implementation of dtypes.
+
+* JSON encoder (but not decoder) has been replaced with a new one. This one
+  is written in pure Python, but is known to outperform CPython's C extension
+  up to **2 times** in some cases. It's about **20 times** faster than
+  the one that we had in 1.6.
+
+* The memory footprint of some of our RPython modules has been drastically
+  improved. This should impact any applications using for example cryptography,
+  like tornado.
+
+* There was some progress in exposing even more CPython C API via cpyext.
+
+Things that didn't make it, expect in 1.8 soon
+==============================================
+
+There is an ongoing work, which while didn't make it to the release, is
+probably worth mentioning here. This is what you should probably expect in
+1.8 some time soon:
+
+* Specialized list implementation. There is a branch that implements lists of
+  integers/floats/strings as compactly as array.array. This should drastically
+  improve performance/memory impact of some applications
+
+* NumPy effort is progressing forward, with multi-dimensional arrays coming
+  soon.
+
+* There are two brand new JIT assembler backends, notably for the PowerPC and
+  ARM processors.
+
+Fundraising
+===========
+
+It's maybe worth mentioning that we're running fundraising campaigns for
+NumPy effort in PyPy and for Python 3 in PyPy. In case you want to see any
+of those happen faster, we urge you to donate to `numpy proposal`_ or
+`py3k proposal`_. In case you want PyPy to progress, but you trust us with
+the general direction, you can always donate to the `general pot`_.
+
+.. _`numpy proposal`: http://pypy.org/numpydonate.html
+.. _`py3k proposal`: http://pypy.org/py3donate.html
+.. _`general pot`: http://pypy.org

File pypy/interpreter/baseobjspace.py

View file
  • Ignore whitespace
         """
         return self.unpackiterable(w_iterable, expected_length)
 
+    def listview_str(self, w_list):
+        """ Return a list of unwrapped strings out of a list of strings. If the
+        argument is not a list or does not contain only strings, return None.
+        May return None anyway.
+        """
+        return None
+
+    def newlist_str(self, list_s):
+        return self.newlist([self.wrap(s) for s in list_s])
+
     @jit.unroll_safe
     def exception_match(self, w_exc_type, w_check_class):
         """Checks if the given exception type matches 'w_check_class'."""

File pypy/interpreter/generator.py

View file
  • Ignore whitespace
+from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.gateway import NoneNotWrapped
+from pypy.interpreter.pyopcode import LoopBlock
 from pypy.rlib import jit
-from pypy.interpreter.pyopcode import LoopBlock
+from pypy.rlib.objectmodel import specialize
 
 
 class GeneratorIterator(Wrappable):
                     break
                 block = block.previous
 
-    def unpack_into(self, results_w):
-        """This is a hack for performance: runs the generator and collects
-        all produced items in a list."""
-        # XXX copied and simplified version of send_ex()
-        space = self.space
-        if self.running:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap('generator already executing'))
-        frame = self.frame
-        if frame is None:    # already finished
-            return
-        self.running = True
-        try:
-            pycode = self.pycode
-            while True:
-                jitdriver.jit_merge_point(self=self, frame=frame,
-                                          results_w=results_w,
-                                          pycode=pycode)
-                try:
-                    w_result = frame.execute_frame(space.w_None)
-                except OperationError, e:
-                    if not e.match(space, space.w_StopIteration):
-                        raise
-                    break
-                # if the frame is now marked as finished, it was RETURNed from
-                if frame.frame_finished_execution:
-                    break
-                results_w.append(w_result)     # YIELDed
-        finally:
-            frame.f_backref = jit.vref_None
-            self.running = False
-            self.frame = None
-
-jitdriver = jit.JitDriver(greens=['pycode'],
-                          reds=['self', 'frame', 'results_w'])
+    # Results can be either an RPython list of W_Root, or it can be an
+    # app-level W_ListObject, which also has an append() method, that's why we
+    # generate 2 versions of the function and 2 jit drivers.
+    def _create_unpack_into():
+        jitdriver = jit.JitDriver(greens=['pycode'],
+                                  reds=['self', 'frame', 'results'])
+        def unpack_into(self, results):
+            """This is a hack for performance: runs the generator and collects
+            all produced items in a list."""
+            # XXX copied and simplified version of send_ex()
+            space = self.space
+            if self.running:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap('generator already executing'))
+            frame = self.frame
+            if frame is None:    # already finished
+                return
+            self.running = True
+            try:
+                pycode = self.pycode
+                while True:
+                    jitdriver.jit_merge_point(self=self, frame=frame,
+                                              results=results, pycode=pycode)
+                    try:
+                        w_result = frame.execute_frame(space.w_None)
+                    except OperationError, e:
+                        if not e.match(space, space.w_StopIteration):
+                            raise
+                        break
+                    # if the frame is now marked as finished, it was RETURNed from
+                    if frame.frame_finished_execution:
+                        break
+                    results.append(w_result)     # YIELDed
+            finally:
+                frame.f_backref = jit.vref_None
+                self.running = False
+                self.frame = None
+        return unpack_into
+    unpack_into = _create_unpack_into()
+    unpack_into_w = _create_unpack_into()

File pypy/interpreter/test/test_function.py

View file
  • Ignore whitespace
         assert isinstance(meth2, Method)
         assert meth2.call_args(args) == obj1
         # Check method returned from unbound_method.__get__()
-        w_meth3 = descr_function_get(space, func, None, space.type(obj2))
+        w_meth3 = descr_function_get(space, func, space.w_None, space.type(obj2))
         meth3 = space.unwrap(w_meth3)
         w_meth4 = meth3.descr_method_get(obj2, space.w_None)
         meth4 = space.unwrap(w_meth4)

File pypy/interpreter/test/test_objspace.py

View file
  • Ignore whitespace
     def test_unpackiterable(self):
         space = self.space
         w = space.wrap
-        l = [w(1), w(2), w(3), w(4)]
+        l = [space.newlist([]) for l in range(4)]
         w_l = space.newlist(l)
-        assert space.unpackiterable(w_l) == l
-        assert space.unpackiterable(w_l, 4) == l
+        l1 = space.unpackiterable(w_l)
+        l2 = space.unpackiterable(w_l, 4)
+        for i in range(4):
+            assert space.is_w(l1[i], l[i])
+            assert space.is_w(l2[i], l[i])
         err = raises(OperationError, space.unpackiterable, w_l, 3)
         assert err.value.match(space, space.w_ValueError)
         err = raises(OperationError, space.unpackiterable, w_l, 5)

File pypy/jit/backend/conftest.py

View file
  • Ignore whitespace
                     help="choose a fixed random seed")
     group.addoption('--backend', action="store",
                     default='llgraph',
-                    choices=['llgraph', 'x86'],
+                    choices=['llgraph', 'cpu'],
                     dest="backend",
                     help="select the backend to run the functions with")
     group.addoption('--block-length', action="store", type="int",

File pypy/jit/backend/llgraph/llimpl.py

View file
  • Ignore whitespace
 from pypy.jit.backend.llgraph import symbolic
 from pypy.jit.codewriter import longlong
 
+from pypy.rlib import libffi
 from pypy.rlib.objectmodel import ComputedIntSymbolic, we_are_translated
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint
     loop = _from_opaque(loop)
     loop.operations.append(Operation(opnum))
 
-def compile_add_descr(loop, ofs, type, arg_types):
+def compile_add_descr(loop, ofs, type, arg_types, extrainfo, width):
     from pypy.jit.backend.llgraph.runner import Descr
     loop = _from_opaque(loop)
     op = loop.operations[-1]
     assert isinstance(type, str) and len(type) == 1
-    op.descr = Descr(ofs, type, arg_types=arg_types)
+    op.descr = Descr(ofs, type, arg_types=arg_types, extrainfo=extrainfo, width=width)
 
 def compile_add_descr_arg(loop, ofs, type, arg_types):
     from pypy.jit.backend.llgraph.runner import Descr
         else:
             raise NotImplementedError
 
+    def op_getinteriorfield_raw(self, descr, array, index):
+        if descr.typeinfo == REF:
+            return do_getinteriorfield_raw_ptr(array, index, descr.width, descr.ofs)
+        elif descr.typeinfo == INT:
+            return do_getinteriorfield_raw_int(array, index, descr.width, descr.ofs)
+        elif descr.typeinfo == FLOAT:
+            return do_getinteriorfield_raw_float(array, index, descr.width, descr.ofs)
+        else:
+            raise NotImplementedError
+
     def op_setinteriorfield_gc(self, descr, array, index, newvalue):
         if descr.typeinfo == REF:
             return do_setinteriorfield_gc_ptr(array, index, descr.ofs,
         else:
             raise NotImplementedError
 
+    def op_setinteriorfield_raw(self, descr, array, index, newvalue):
+        if descr.typeinfo == REF:
+            return do_setinteriorfield_raw_ptr(array, index, newvalue, descr.width, descr.ofs)
+        elif descr.typeinfo == INT:
+            return do_setinteriorfield_raw_int(array, index, newvalue, descr.width, descr.ofs)
+        elif descr.typeinfo == FLOAT:
+            return do_setinteriorfield_raw_float(array, index, newvalue, descr.width, descr.ofs)
+        else:
+            raise NotImplementedError
+
     def op_setfield_gc(self, fielddescr, struct, newvalue):
         if fielddescr.typeinfo == REF:
             do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue)
     struct = array._obj.container.getitem(index)
     return cast_to_ptr(_getinteriorfield_gc(struct, fieldnum))
 
+def _getinteriorfield_raw(ffitype, array, index, width, ofs):
+    addr = rffi.cast(rffi.VOIDP, array)
+    return libffi.array_getitem(ffitype, width, addr, index, ofs)
+
+def do_getinteriorfield_raw_int(array, index, width, ofs):
+    res = _getinteriorfield_raw(libffi.types.slong, array, index, width, ofs)
+    return res
+
 def _getfield_raw(struct, fieldnum):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
     ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
     return do_setinteriorfield_gc
 do_setinteriorfield_gc_int = new_setinteriorfield_gc(cast_from_int)
 do_setinteriorfield_gc_float = new_setinteriorfield_gc(cast_from_floatstorage)
-do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)        
+do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)
+
+def new_setinteriorfield_raw(ffitype):
+    def do_setinteriorfield_raw(array, index, newvalue, width, ofs):
+        addr = rffi.cast(rffi.VOIDP, array)
+        return libffi.array_setitem(ffitype, width, addr, index, ofs, newvalue)
+    return do_setinteriorfield_raw
+do_setinteriorfield_raw_int = new_setinteriorfield_raw(libffi.types.slong)
 
 def do_setfield_raw_int(struct, fieldnum, newvalue):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]

File pypy/jit/backend/llgraph/runner.py

View file
  • Ignore whitespace
 class Descr(history.AbstractDescr):
 
     def __init__(self, ofs, typeinfo, extrainfo=None, name=None,
-                 arg_types=None, count_fields_if_immut=-1, ffi_flags=0):
+                 arg_types=None, count_fields_if_immut=-1, ffi_flags=0, width=-1):
+
         self.ofs = ofs
+        self.width = width
         self.typeinfo = typeinfo
         self.extrainfo = extrainfo
         self.name = name
         return False
 
     def getdescr(self, ofs, typeinfo='?', extrainfo=None, name=None,
-                 arg_types=None, count_fields_if_immut=-1, ffi_flags=0):
+                 arg_types=None, count_fields_if_immut=-1, ffi_flags=0, width=-1):
         key = (ofs, typeinfo, extrainfo, name, arg_types,
-               count_fields_if_immut, ffi_flags)
+               count_fields_if_immut, ffi_flags, width)
         try:
             return self._descrs[key]
         except KeyError:
             descr = Descr(ofs, typeinfo, extrainfo, name, arg_types,
-                          count_fields_if_immut, ffi_flags)
+                          count_fields_if_immut, ffi_flags, width)
             self._descrs[key] = descr
             return descr
 
             descr = op.getdescr()
             if isinstance(descr, Descr):
                 llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo,
-                                         descr.arg_types)
+                                         descr.arg_types, descr.extrainfo,
+                                         descr.width)
             if (isinstance(descr, history.LoopToken) and
                 op.getopnum() != rop.JUMP):
                 llimpl.compile_add_loop_token(c, descr)
 
     def interiorfielddescrof(self, A, fieldname):
         S = A.OF
-        ofs2 = symbolic.get_size(A)
+        width = symbolic.get_size(A)
         ofs, size = symbolic.get_field_token(S, fieldname)
         token = history.getkind(getattr(S, fieldname))
-        return self.getdescr(ofs, token[0], name=fieldname, extrainfo=ofs2)
+        return self.getdescr(ofs, token[0], name=fieldname, width=width)
+
+    def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
+        is_pointer, is_float, is_signed):
+
+        if is_pointer:
+            typeinfo = REF
+        elif is_float:
+            typeinfo = FLOAT
+        else:
+            typeinfo = INT
+        # we abuse the arg_types field to distinguish dynamic and static descrs
+        return Descr(offset, typeinfo, arg_types='dynamic', name='<dynamic interior field>', width=width)
 
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
         arg_types = []

File pypy/jit/backend/llsupport/descr.py

View file
  • Ignore whitespace
     def repr_of_descr(self):
         return '<%s %s %s>' % (self._clsname, self.name, self.offset)
 
+class DynamicFieldDescr(BaseFieldDescr):
+    def __init__(self, offset, fieldsize, is_pointer, is_float, is_signed):
+        self.offset = offset
+        self._fieldsize = fieldsize
+        self._is_pointer_field = is_pointer
+        self._is_float_field = is_float
+        self._is_field_signed = is_signed
+
+    def get_field_size(self, translate_support_code):
+        return self._fieldsize
 
 class NonGcPtrFieldDescr(BaseFieldDescr):
     _clsname = 'NonGcPtrFieldDescr'
     def repr_of_descr(self):
         return '<%s>' % self._clsname
 
+
 class NonGcPtrArrayDescr(BaseArrayDescr):
     _clsname = 'NonGcPtrArrayDescr'
     def get_item_size(self, translate_support_code):
     def get_ofs_length(self, translate_support_code):
         return -1
 
+class DynamicArrayNoLengthDescr(BaseArrayNoLengthDescr):
+    def __init__(self, itemsize):
+        self.itemsize = itemsize
+
+    def get_item_size(self, translate_support_code):
+        return self.itemsize
+
 class NonGcPtrArrayNoLengthDescr(BaseArrayNoLengthDescr):
     _clsname = 'NonGcPtrArrayNoLengthDescr'
     def get_item_size(self, translate_support_code):

File pypy/jit/backend/llsupport/llmodel.py

View file
  • Ignore whitespace
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes
 from pypy.jit.backend.llsupport.descr import (get_size_descr,
-     get_field_descr, BaseFieldDescr, get_array_descr, BaseArrayDescr,
-     get_call_descr, BaseIntCallDescr, GcPtrCallDescr, FloatCallDescr,
-     VoidCallDescr, InteriorFieldDescr, get_interiorfield_descr)
+     get_field_descr, BaseFieldDescr, DynamicFieldDescr, get_array_descr,
+     BaseArrayDescr, DynamicArrayNoLengthDescr, get_call_descr,
+     BaseIntCallDescr, GcPtrCallDescr, FloatCallDescr, VoidCallDescr,
+     InteriorFieldDescr, get_interiorfield_descr)
 from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
 
 
     def interiorfielddescrof(self, A, fieldname):
         return get_interiorfield_descr(self.gc_ll_descr, A, A.OF, fieldname)
 
+    def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
+        is_pointer, is_float, is_signed):
+        arraydescr = DynamicArrayNoLengthDescr(width)
+        fielddescr = DynamicFieldDescr(offset, fieldsize, is_pointer, is_float, is_signed)
+        return InteriorFieldDescr(arraydescr, fielddescr)
+
     def unpack_arraydescr(self, arraydescr):
         assert isinstance(arraydescr, BaseArrayDescr)
         return arraydescr.get_base_size(self.translate_support_code)

File pypy/jit/backend/llsupport/test/test_gc.py

  • Ignore whitespace
File contents unchanged.

File pypy/jit/backend/model.py

View file
  • Ignore whitespace
             lst[n] = None
         self.fail_descr_free_list.extend(faildescr_indices)
 
-    @staticmethod
-    def sizeof(S):
+    def sizeof(self, S):
         raise NotImplementedError
 
-    @staticmethod
-    def fielddescrof(S, fieldname):
+    def fielddescrof(self, S, fieldname):
         """Return the Descr corresponding to field 'fieldname' on the
         structure 'S'.  It is important that this function (at least)
         caches the results."""
         raise NotImplementedError
 
-    @staticmethod
-    def arraydescrof(A):
+    def interiorfielddescrof(self, A, fieldname):
         raise NotImplementedError
 
-    @staticmethod
-    def calldescrof(FUNC, ARGS, RESULT):
+    def interiorfielddescrof_dynamic(self, offset, width, fieldsize, is_pointer,
+        is_float, is_signed):
+        raise NotImplementedError
+
+    def arraydescrof(self, A):
+        raise NotImplementedError
+
+    def calldescrof(self, FUNC, ARGS, RESULT):
         # FUNC is the original function type, but ARGS is a list of types
         # with Voids removed
         raise NotImplementedError
 
-    @staticmethod
-    def methdescrof(SELFTYPE, methname):
+    def methdescrof(self, SELFTYPE, methname):
         # must return a subclass of history.AbstractMethDescr
         raise NotImplementedError
 
-    @staticmethod
-    def typedescrof(TYPE):
-        raise NotImplementedError
-
-    @staticmethod
-    def interiorfielddescrof(A, fieldname):
+    def typedescrof(self, TYPE):
         raise NotImplementedError
 
     # ---------- the backend-dependent operations ----------

File pypy/jit/backend/test/test_random.py

View file
  • Ignore whitespace
     if pytest.config.option.backend == 'llgraph':
         from pypy.jit.backend.llgraph.runner import LLtypeCPU
         return LLtypeCPU(None)
-    elif pytest.config.option.backend == 'x86':
-        from pypy.jit.backend.x86.runner import CPU386
-        return CPU386(None, None)
+    elif pytest.config.option.backend == 'cpu':
+        from pypy.jit.backend.detect_cpu import getcpuclass
+        return getcpuclass()(None, None)
     else:
         assert 0, "unknown backend %r" % pytest.config.option.backend
 

File pypy/jit/backend/test/test_zll_stress.py

View file
  • Ignore whitespace
+from pypy.jit.backend.test.test_random import check_random_function, Random
+from pypy.jit.backend.test.test_ll_random import LLtypeOperationBuilder
+from pypy.jit.backend.detect_cpu import getcpuclass
+
+CPU = getcpuclass()
+
+def test_stress():
+    cpu = CPU(None, None)
+    cpu.setup_once()
+    r = Random()
+    for i in range(1000):
+        check_random_function(cpu, LLtypeOperationBuilder, r, i, 1000)

File pypy/jit/backend/x86/assembler.py

View file
  • Ignore whitespace
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
 from pypy.jit.backend.model import CompiledLoopToken
-from pypy.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs,
-                                           _get_scale, gpr_reg_mgr_cls)
+from pypy.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs, _get_scale,
+    gpr_reg_mgr_cls, _valid_addressing_size)
 
 from pypy.jit.backend.x86.arch import (FRAME_FIXED_SIZE, FORCE_INDEX_OFS, WORD,
                                        IS_X86_32, IS_X86_64)
         assert isinstance(itemsize_loc, ImmedLoc)
         if isinstance(index_loc, ImmedLoc):
             temp_loc = imm(index_loc.value * itemsize_loc.value)
+        elif _valid_addressing_size(itemsize_loc.value):
+            return AddressLoc(base_loc, index_loc, _get_scale(itemsize_loc.value), ofs_loc.value)
         else:
-            # XXX should not use IMUL in most cases
+            # XXX should not use IMUL in more cases, it can use a clever LEA
             assert isinstance(temp_loc, RegLoc)
             assert isinstance(index_loc, RegLoc)
             assert not temp_loc.is_xmm
                                                 ofs_loc)
         self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc)
 
+    genop_getinteriorfield_raw = genop_getinteriorfield_gc
+
 
     def genop_discard_setfield_gc(self, op, arglocs):
         base_loc, ofs_loc, size_loc, value_loc = arglocs
                                                  ofs_loc)
         self.save_into_mem(dest_addr, value_loc, fieldsize_loc)
 
+    genop_discard_setinteriorfield_raw = genop_discard_setinteriorfield_gc
+
     def genop_discard_setarrayitem_gc(self, op, arglocs):
         base_loc, ofs_loc, value_loc, size_loc, baseofs = arglocs
         assert isinstance(baseofs, ImmedLoc)

File pypy/jit/backend/x86/codebuf.py

  • Ignore whitespace
File contents unchanged.

File pypy/jit/backend/x86/regalloc.py

View file
  • Ignore whitespace
         self.PerformDiscard(op, [base_loc, ofs, itemsize, fieldsize,
                                  index_loc, temp_loc, value_loc])
 
+    consider_setinteriorfield_raw = consider_setinteriorfield_gc
+
     def consider_strsetitem(self, op):
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
         self.Perform(op, [base_loc, ofs, itemsize, fieldsize,
                           index_loc, temp_loc, sign_loc], result_loc)
 
+    consider_getinteriorfield_raw = consider_getinteriorfield_gc
+
     def consider_int_is_true(self, op, guard_op):
         # doesn't need arg to be in a register
         argloc = self.loc(op.getarg(0))
     # i.e. the n'th word beyond the fixed frame size.
     return -WORD * (FRAME_FIXED_SIZE + position)
 
+def _valid_addressing_size(size):
+    return size == 1 or size == 2 or size == 4 or size == 8
+
 def _get_scale(size):
-    assert size == 1 or size == 2 or size == 4 or size == 8
+    assert _valid_addressing_size(size)
     if size < 4:
         return size - 1         # 1, 2 => 0, 1
     else:

File pypy/jit/backend/x86/runner.py

  • Ignore whitespace
File contents unchanged.

File pypy/jit/backend/x86/test/test_assembler.py

  • Ignore whitespace
File contents unchanged.

File pypy/jit/backend/x86/test/test_fficall.py

View file
  • Ignore whitespace
+import py
+from pypy.jit.metainterp.test import test_fficall
+from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
+
+class TestFfiLookups(Jit386Mixin, test_fficall.FfiLookupTests):
+    # for the individual tests see
+    # ====> ../../../metainterp/test/test_fficall.py
+    supports_all = True

File pypy/jit/backend/x86/test/test_zll_random.py

  • Ignore whitespace
-from pypy.jit.backend.test.test_random import check_random_function, Random
-from pypy.jit.backend.test.test_ll_random import LLtypeOperationBuilder
-from pypy.jit.backend.detect_cpu import getcpuclass
-
-CPU = getcpuclass()
-
-def test_stress():
-    cpu = CPU(None, None)
-    cpu.setup_once()
-    r = Random()
-    for i in range(1000):
-        check_random_function(cpu, LLtypeOperationBuilder, r, i, 1000)

File pypy/jit/backend/x86/test/test_ztranslation.py

View file
  • Ignore whitespace
 import py, os, sys
 from pypy.tool.udir import udir
-from pypy.rlib.jit import JitDriver, unroll_parameters
+from pypy.rlib.jit import JitDriver, unroll_parameters, set_param
 from pypy.rlib.jit import PARAMETERS, dont_look_inside
 from pypy.rlib.jit import promote
 from pypy.jit.metainterp.jitprof import Profiler
         def f(i, j):
             for param, _ in unroll_parameters:
                 defl = PARAMETERS[param]
-                jitdriver.set_param(param, defl)
-            jitdriver.set_param("threshold", 3)
-            jitdriver.set_param("trace_eagerness", 2)
+                set_param(jitdriver, param, defl)
+            set_param(jitdriver, "threshold", 3)
+            set_param(jitdriver, "trace_eagerness", 2)
             total = 0
             frame = Frame(i)
             while frame.i > 3:
             else:
                 return Base()
         def myportal(i):
-            jitdriver.set_param("threshold", 3)
-            jitdriver.set_param("trace_eagerness", 2)
+            set_param(jitdriver, "threshold", 3)
+            set_param(jitdriver, "trace_eagerness", 2)
             total = 0
             n = i
             while True:

File pypy/jit/codewriter/codewriter.py

View file
  • Ignore whitespace
         else:
             name = 'unnamed' % id(ssarepr)
         i = 1
+        # escape <lambda> names for windows
+        name = name.replace('<lambda>', '_(lambda)_')
         extra = ''
         while name+extra in self._seen_files:
             i += 1

File pypy/jit/codewriter/effectinfo.py

View file
  • Ignore whitespace
     OS_LIBFFI_PREPARE           = 60
     OS_LIBFFI_PUSH_ARG          = 61
     OS_LIBFFI_CALL              = 62
+    OS_LIBFFI_GETARRAYITEM      = 63
+    OS_LIBFFI_SETARRAYITEM      = 64
     #
     OS_LLONG_INVERT             = 69
     OS_LLONG_ADD                = 70

File pypy/jit/codewriter/jtransform.py

View file
  • Ignore whitespace
         elif oopspec_name.startswith('libffi_call_'):
             oopspecindex = EffectInfo.OS_LIBFFI_CALL
             extraeffect = EffectInfo.EF_RANDOM_EFFECTS
+        elif oopspec_name == 'libffi_array_getitem':
+            oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
+        elif oopspec_name == 'libffi_array_setitem':
+            oopspecindex = EffectInfo.OS_LIBFFI_SETARRAYITEM
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
         else:
             assert False, 'unsupported oopspec: %s' % oopspec_name
         return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)

File pypy/jit/metainterp/executor.py

View file
  • Ignore whitespace
                          rop.DEBUG_MERGE_POINT,
                          rop.JIT_DEBUG,
                          rop.SETARRAYITEM_RAW,
+                         rop.GETINTERIORFIELD_RAW,
+                         rop.SETINTERIORFIELD_RAW,
                          rop.CALL_RELEASE_GIL,
                          rop.QUASIIMMUT_FIELD,
                          ):      # list of opcodes never executed by pyjitpl

File pypy/jit/metainterp/heapcache.py

  • Ignore whitespace
File contents unchanged.

File pypy/jit/metainterp/optimizeopt/fficall.py

View file
  • Ignore whitespace
+from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.rlib import clibffi, libffi
+from pypy.rlib.debug import debug_print
+from pypy.rlib.libffi import Func
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.libffi import Func
-from pypy.rlib.debug import debug_print
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.rpython.lltypesystem import llmemory
 
 
 class FuncInfo(object):
 
     def new(self):
         return OptFfiCall()
-    
+
     def begin_optimization(self, funcval, op):
         self.rollback_maybe('begin_optimization', op)
         self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op)
             ops = self.do_push_arg(op)
         elif oopspec == EffectInfo.OS_LIBFFI_CALL:
             ops = self.do_call(op)
+        elif (oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM or
+            oopspec == EffectInfo.OS_LIBFFI_SETARRAYITEM):
+            ops = self.do_getsetarrayitem(op, oopspec)
         #
         for op in ops:
             self.emit_operation(op)
         ops.append(newop)
         return ops
 
+    def do_getsetarrayitem(self, op, oopspec):
+        ffitypeval = self.getvalue(op.getarg(1))
+        widthval = self.getvalue(op.getarg(2))
+        offsetval = self.getvalue(op.getarg(5))
+        if not ffitypeval.is_constant() or not widthval.is_constant() or not offsetval.is_constant():
+            return [op]
+
+        ffitypeaddr = ffitypeval.box.getaddr()
+        ffitype = llmemory.cast_adr_to_ptr(ffitypeaddr, clibffi.FFI_TYPE_P)
+        offset = offsetval.box.getint()
+        width = widthval.box.getint()
+        descr = self._get_interior_descr(ffitype, width, offset)
+
+        arglist = [
+            self.getvalue(op.getarg(3)).force_box(self.optimizer),
+            self.getvalue(op.getarg(4)).force_box(self.optimizer),
+        ]
+        if oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM:
+            opnum = rop.GETINTERIORFIELD_RAW
+        elif oopspec == EffectInfo.OS_LIBFFI_SETARRAYITEM:
+            opnum = rop.SETINTERIORFIELD_RAW
+            arglist.append(self.getvalue(op.getarg(6)).force_box(self.optimizer))
+        else:
+            assert False
+        return [
+            ResOperation(opnum, arglist, op.result, descr=descr),
+        ]
+
+    def _get_interior_descr(self, ffitype, width, offset):
+        kind = libffi.types.getkind(ffitype)
+        is_pointer = is_float = is_signed = False
+        if ffitype is libffi.types.pointer:
+            is_pointer = True
+        elif kind == 'i':
+            is_signed = True
+        elif kind == 'f' or kind == 'I' or kind == 'U':
+            # longlongs are treated as floats, see
+            # e.g. llsupport/descr.py:getDescrClass
+            is_float = True
+        else:
+            assert False, "unsupported ffitype or kind"
+        #
+        fieldsize = ffitype.c_size
+        return self.optimizer.cpu.interiorfielddescrof_dynamic(
+            offset, width, fieldsize, is_pointer, is_float, is_signed
+        )
+
     def propagate_forward(self, op):
         if self.logops is not None:
             debug_print(self.logops.repr_of_resop(op))

File pypy/jit/metainterp/optimizeopt/optimizer.py

View file
  • Ignore whitespace
         self.opaque_pointers = {}
         self.replaces_guard = {}
         self._newoperations = []
+        self.seen_results = {}
         self.optimizer = self
         self.optpure = None
         self.optearlyforce = None
                 op = self.store_final_boxes_in_guard(op)
         elif op.can_raise():
             self.exception_might_have_happened = True
+        if op.result:
+            if op.result in self.seen_results:
+                raise ValueError, "invalid optimization"
+            self.seen_results[op.result] = None
         self._newoperations.append(op)
 
     def replace_op(self, old_op, new_op):

File pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py

View file
  • Ignore whitespace
         """
         self.optimize_loop(ops, expected, preamble)
 
+    def test_virtual_recursive(self):
+        ops = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        i1 = int_add(i0, 1)
+        setfield_gc(p2, i1, descr=valuedescr)
+        jump(p1)
+        """
+        preamble = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        i3 = int_add(i0, 1)
+        jump(i3)
+        """
+        expected = """
+        [i0]
+        i1 = int_add(i0, 1)
+        jump(i1)
+        """
+        self.optimize_loop(ops, expected, preamble)
+
+    def test_virtual_recursive_forced(self):
+        ops = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        i1 = int_add(i0, 1)
+        setfield_gc(p2, i1, descr=valuedescr)
+        setfield_gc(p0, p1, descr=nextdescr)
+        jump(p1)
+        """
+        preamble = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        i1 = int_add(i0, 1)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p2, i1, descr=valuedescr)
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        setfield_gc(p0, p1, descr=nextdescr)
+        jump(p1)
+        """
+        loop = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        i1 = int_add(i0, 1)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p0, p1, descr=nextdescr)
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        setfield_gc(p2, i1, descr=valuedescr)
+        jump(p1)
+        """
+        self.optimize_loop(ops, loop, preamble)
+
     def test_virtual_constant_isnull(self):
         ops = """
         [i0]
         jump()
         """
         self.optimize_loop(ops, expected)
+        # ----------
+        ops = """
+        [p1]
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        setfield_gc(p0, p1, descr=immut_ptrval)
+        escape(p0)
+        jump(p1)
+        """
+        self.optimize_loop(ops, ops)
+        # ----------
+        ops = """
+        []
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        p1 = new_with_vtable(ConstClass(intobj_immut_vtable))
+        setfield_gc(p1, 1242, descr=immut_intval)
+        setfield_gc(p0, p1, descr=immut_ptrval)
+        escape(p0)
+        jump()
+        """
+        class PtrObj1242(object):
+            _TYPE = llmemory.GCREF.TO
+            def __eq__(slf, other):
+                if slf is other:
+                    return 1
+                p1 = other.container.ptrval
+                p1cast = lltype.cast_pointer(lltype.Ptr(self.INTOBJ_IMMUT), p1)
+                return p1cast.intval == 1242
+        self.namespace['ptrobj1242'] = lltype._ptr(llmemory.GCREF,
+                                                   PtrObj1242())
+        expected = """
+        []
+        escape(ConstPtr(ptrobj1242))
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_immutable_constantfold_recursive(self):
+        ops = """
+        []
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        setfield_gc(p0, p0, descr=immut_ptrval)
+        escape(p0)
+        jump()
+        """
+        from pypy.rpython.lltypesystem import lltype, llmemory
+        class PtrObjSelf(object):
+            _TYPE = llmemory.GCREF.TO
+            def __eq__(slf, other):
+                if slf is other:
+                    return 1
+                p1 = other.container.ptrval
+                p1cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p1)
+                return p1cast.ptrval == p1
+        self.namespace['ptrobjself'] = lltype._ptr(llmemory.GCREF,
+                                                   PtrObjSelf())
+        expected = """
+        []
+        escape(ConstPtr(ptrobjself))
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+        #
+        ops = """
+        []
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        p1 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        setfield_gc(p0, p1, descr=immut_ptrval)
+        setfield_gc(p1, p0, descr=immut_ptrval)
+        escape(p0)
+        jump()
+        """
+        class PtrObjSelf2(object):
+            _TYPE = llmemory.GCREF.TO
+            def __eq__(slf, other):
+                if slf is other:
+                    return 1
+                p1 = other.container.ptrval
+                p1cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p1)
+                p2 = p1cast.ptrval
+                assert p2 != p1
+                p2cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p2)
+                return p2cast.ptrval == p1
+        self.namespace['ptrobjself2'] = lltype._ptr(llmemory.GCREF,
+                                                    PtrObjSelf2())
+        expected = """
+        []
+        escape(ConstPtr(ptrobjself2))
+        jump()
+        """
+        self.optimize_loop(ops, expected)
 
     # ----------
     def optimize_strunicode_loop(self, ops, optops, preamble):

File pypy/jit/metainterp/optimizeopt/test/test_util.py

View file
  • Ignore whitespace
     noimmut_intval = cpu.fielddescrof(INTOBJ_NOIMMUT, 'intval')
     immut_intval = cpu.fielddescrof(INTOBJ_IMMUT, 'intval')
 
+    PTROBJ_IMMUT = lltype.GcStruct('PTROBJ_IMMUT', ('parent', OBJECT),
+                                            ('ptrval', lltype.Ptr(OBJECT)),
+                                            hints={'immutable': True})
+    ptrobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+    immut_ptrval = cpu.fielddescrof(PTROBJ_IMMUT, 'ptrval')
+
     arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed))
     floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float))
 
     register_known_gctype(cpu, jit_virtual_ref_vtable,vrefinfo.JIT_VIRTUAL_REF)
     register_known_gctype(cpu, intobj_noimmut_vtable, INTOBJ_NOIMMUT)
     register_known_gctype(cpu, intobj_immut_vtable,   INTOBJ_IMMUT)
+    register_known_gctype(cpu, ptrobj_immut_vtable,   PTROBJ_IMMUT)
 
     namespace = locals()
 

File pypy/jit/metainterp/optimizeopt/virtualize.py

View file
  • Ignore whitespace
     def _get_descr(self):
         raise NotImplementedError
 
-    def _is_immutable_and_filled_with_constants(self, optforce):
+    def _is_immutable_and_filled_with_constants(self, memo=None):
+        # check if it is possible to force the given structure into a
+        # compile-time constant: this is allowed only if it is declared
+        # immutable, if all fields are already filled, and if each field
+        # is either a compile-time constant or (recursively) a structure
+        # which also answers True to the same question.
+        #
+        # check that all fields are filled.  The following equality check
+        # also fails if count == -1, meaning "not an immutable at all".
         count = self._get_descr().count_fields_if_immutable()
-        if count != len(self._fields):    # always the case if count == -1
+        if count != len(self._fields):
             return False
+        #
+        # initialize 'memo'
+        if memo is None:
+            memo = {}
+        elif self in memo:
+            return True   # recursive case: assume yes
+        memo[self] = None
+        #
         for value in self._fields.itervalues():
-            subbox = value.force_box(optforce)
-            if not isinstance(subbox, Const):
-                return False
+            if value.is_constant():
+                pass            # it is a constant value: ok
+            elif (isinstance(value, AbstractVirtualStructValue)
+                  and value.is_virtual()):
+                # recursive check
+                if not value._is_immutable_and_filled_with_constants(memo):
+                    return False
+            else:
+                return False    # not a constant at all
         return True
 
     def force_at_end_of_preamble(self, already_forced, optforce):
         if not we_are_translated():
             op.name = 'FORCE ' + self.source_op.name
 
-        if self._is_immutable_and_filled_with_constants(optforce):
+        if self._is_immutable_and_filled_with_constants():
             box = optforce.optimizer.constant_fold(op)
             self.make_constant(box)
             for ofs, value in self._fields.iteritems():

File pypy/jit/metainterp/pyjitpl.py

  • Ignore whitespace
File contents unchanged.

File pypy/jit/metainterp/resoperation.py

View file
  • Ignore whitespace
     'GETARRAYITEM_GC/2d',
     'GETARRAYITEM_RAW/2d',
     'GETINTERIORFIELD_GC/2d',
+    'GETINTERIORFIELD_RAW/2d',
     'GETFIELD_GC/1d',
     'GETFIELD_RAW/1d',
     '_MALLOC_FIRST',
     'SETARRAYITEM_GC/3d',
     'SETARRAYITEM_RAW/3d',
     'SETINTERIORFIELD_GC/3d',
+    'SETINTERIORFIELD_RAW/3d',
     'SETFIELD_GC/2d',
     'SETFIELD_RAW/2d',
     'STRSETITEM/3',

File pypy/jit/metainterp/test/test_ajit.py

View file
  • Ignore whitespace
 from pypy.rlib.jit import (JitDriver, we_are_jitted, hint, dont_look_inside,
     loop_invariant, elidable, promote, jit_debug, assert_green,
     AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
-    isconstant, isvirtual, promote_string)
+    isconstant, isvirtual, promote_string, set_param)
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.ootypesystem import ootype
                 n -= 1
                 x += n
             return x
-        def f(n, threshold):
-            myjitdriver.set_param('threshold', threshold)
+        def f(n, threshold, arg):
+            if arg:
+                set_param(myjitdriver, 'threshold', threshold)
+            else:
+                set_param(None, 'threshold', threshold)
             return g(n)
 
-        res = self.meta_interp(f, [10, 3])
+        res = self.meta_interp(f, [10, 3, 1])
         assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
         self.check_tree_loop_count(2)
 
-        res = self.meta_interp(f, [10, 13])
+        res = self.meta_interp(f, [10, 13, 0])
         assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
         self.check_tree_loop_count(0)
 
                                 get_printable_location=get_printable_location)
         bytecode = "0j10jc20a3"
         def f():
-            myjitdriver.set_param('threshold', 7)
-            myjitdriver.set_param('trace_eagerness', 1)
+            set_param(myjitdriver, 'threshold', 7)
+            set_param(myjitdriver, 'trace_eagerness', 1)
             i = j = c = a = 1
             while True:
                 myjitdriver.jit_merge_point(i=i, j=j, c=c, a=a)
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
 
         def f(n, limit):
-            myjitdriver.set_param('retrace_limit', limit)
+            set_param(myjitdriver, 'retrace_limit', limit)
             sa = i = a = 0
             while i < n:
                 myjitdriver.jit_merge_point(n=n, i=i, sa=sa, a=a)
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
 
         def f(n, limit):
-            myjitdriver.set_param('retrace_limit', 3)
-            myjitdriver.set_param('max_retrace_guards', limit)
+            set_param(myjitdriver, 'retrace_limit', 3)
+            set_param(myjitdriver, 'max_retrace_guards', limit)
             sa = i = a = 0
             while i < n:
                 myjitdriver.jit_merge_point(n=n, i=i, sa=sa, a=a)
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a',
                                                      'node'])
         def f(n, limit):
-            myjitdriver.set_param('retrace_limit', limit)
+            set_param(myjitdriver, 'retrace_limit', limit)
             sa = i = a = 0
             node = [1, 2, 3]
             node[1] = n
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa'])
         bytecode = "0+sI0+SI"
         def f(n):
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 1)
-            myjitdriver.set_param('retrace_limit', 5)
-            myjitdriver.set_param('function_threshold', -1)
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 1)
+            set_param(None, 'retrace_limit', 5)
+            set_param(None, 'function_threshold', -1)
             pc = sa = i = 0
             while pc < len(bytecode):
                 myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i)
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'a', 'i', 'j', 'sa'])
         bytecode = "ij+Jj+JI"
         def f(n, a):
-            myjitdriver.set_param('threshold', 5)
-            myjitdriver.set_param('trace_eagerness', 1)
-            myjitdriver.set_param('retrace_limit', 2)
+            set_param(None, 'threshold', 5)
+            set_param(None, 'trace_eagerness', 1)
+            set_param(None, 'retrace_limit', 2)
             pc = sa = i = j = 0
             while pc < len(bytecode):
                 myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i, j=j, a=a)
                 return B(self.val + 1)
         myjitdriver = JitDriver(greens = [], reds = ['sa', 'a'])
         def f():
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 2)
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 2)
             a = A(0)
             sa = 0
             while a.val < 8:
                 return B(self.val + 1)
         myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a'])
         def f(b):
-            myjitdriver.set_param('threshold', 6)
-            myjitdriver.set_param('trace_eagerness', 4)
+            set_param(None, 'threshold', 6)
+            set_param(None, 'trace_eagerness', 4)
             a = A(0)
             sa = 0
             while a.val < 15:
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa'])
         bytecode = "0+sI0+SI"
         def f(n):
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 1)
-            myjitdriver.set_param('retrace_limit', 5)
-            myjitdriver.set_param('function_threshold', -1)
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 1)
+            set_param(None, 'retrace_limit', 5)
+            set_param(None, 'function_threshold', -1)
             pc = sa = i = 0
             while pc < len(bytecode):
                 myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i)

File pypy/jit/metainterp/test/test_fficall.py

View file
  • Ignore whitespace
+import py
 
-import py
+from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.rlib.jit import JitDriver, promote, dont_look_inside
+from pypy.rlib.libffi import (ArgChain, IS_32_BIT, array_getitem, array_setitem,
+    types)
+from pypy.rlib.objectmodel import specialize
 from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
-from pypy.rlib.jit import JitDriver, promote, dont_look_inside
+from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.libffi import ArgChain
-from pypy.rlib.libffi import IS_32_BIT
-from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib.objectmodel import specialize
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.jit.metainterp.test.support import LLJitMixin
 
-class TestFfiCall(LLJitMixin, _TestLibffiCall):
-    supports_all = False     # supports_{floats,longlong,singlefloats}
 
+class FfiCallTests(_TestLibffiCall):