Author: Alex Gaynor <[email protected]>
Branch: 
Changeset: r59085:d25f52b5e8ff
Date: 2012-11-25 10:16 -0600
http://bitbucket.org/pypy/pypy/changeset/d25f52b5e8ff/

Log:    merged upstream

diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -2,3 +2,4 @@
 b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked
 d8ac7d23d3ec5f9a0fa1264972f74a010dbfd07f release-1.6
 ff4af8f318821f7f5ca998613a60fca09aa137da release-1.7
+07e08e9c885ca67d89bcc304e45a32346daea2fa release-2.0-beta-1
diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst
--- a/pypy/doc/jit-hooks.rst
+++ b/pypy/doc/jit-hooks.rst
@@ -5,62 +5,36 @@
 understanding what's pypy's JIT doing while running your program. There
 are three functions related to that coming from the `pypyjit` module:
 
-* `set_optimize_hook`::
+* `set_optimize_hook(callable)`::
 
     Set a compiling hook that will be called each time a loop is optimized,
-    but before assembler compilation. This allows to add additional
+    but before assembler compilation. This allows adding additional
     optimizations on Python level.
-    
-    The hook will be called with the following signature:
-    hook(jitdriver_name, loop_type, greenkey or guard_number, operations)
 
-    jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
-    the main interpreter loop
+    The callable will be called with the pypyjit.JitLoopInfo object.
+    Refer to it's documentation for details.
 
-    loop_type can be either `loop` `entry_bridge` or `bridge`
-    in case loop is not `bridge`, greenkey will be a tuple of constants
-    or a string describing it.
+    Result value will be the resulting list of operations, or None
 
-    for the interpreter loop` it'll be a tuple
-    (code, offset, is_being_profiled)
+
+* `set_compile_hook(callable)`::
+
+    Set a compiling hook that will be called each time a loop is compiled.
+
+    The callable will be called with the pypyjit.JitLoopInfo object.
+    Refer to it's documentation for details.
 
     Note that jit hook is not reentrant. It means that if the code
     inside the jit hook is itself jitted, it will get compiled, but the
     jit hook won't be called for that.
 
-    Result value will be the resulting list of operations, or None
-
-* `set_compile_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(jitdriver_name, loop_type, greenkey or guard_number, operations,
-         assembler_addr, assembler_length)
-
-    jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
-    the main interpreter loop
-
-    loop_type can be either `loop` `entry_bridge` or `bridge`
-    in case loop is not `bridge`, greenkey will be a tuple of constants
-    or a string describing it.
-
-    for the interpreter loop` it'll be a tuple
-    (code, offset, is_being_profiled)
-
-    assembler_addr is an integer describing where assembler starts,
-    can be accessed via ctypes, assembler_lenght is the lenght of compiled
-    asm
-
-    Note that jit hook is not reentrant. It means that if the code
-    inside the jit hook is itself jitted, it will get compiled, but the
-    jit hook won't be called for that.
-
-* `set_abort_hook`::
+* `set_abort_hook(hook)`::
 
     Set a hook (callable) that will be called each time there is tracing
     aborted due to some reason.
 
     The hook will be called as in: hook(jitdriver_name, greenkey, reason)
 
-    Where reason is the reason for abort, see documentation for 
set_compile_hook
-    for descriptions of other arguments.
+    Reason is a string, the meaning of other arguments is the same
+    as attributes on JitLoopInfo object
+
diff --git a/pypy/interpreter/astcompiler/optimize.py 
b/pypy/interpreter/astcompiler/optimize.py
--- a/pypy/interpreter/astcompiler/optimize.py
+++ b/pypy/interpreter/astcompiler/optimize.py
@@ -141,7 +141,7 @@
 unrolling_unary_folders = unrolling_iterable(unary_folders.items())
 
 for folder in binary_folders.values() + unary_folders.values():
-    folder._always_inline_ = True
+    folder._always_inline_ = 'try'
 del folder
 
 opposite_compare_operations = misc.dict_to_switch({
diff --git a/pypy/interpreter/executioncontext.py 
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -144,7 +144,10 @@
         actionflag = self.space.actionflag
         if actionflag.get_ticker() < 0:
             actionflag.action_dispatcher(self, frame)     # slow path
-    bytecode_trace_after_exception._always_inline_ = True
+    bytecode_trace_after_exception._always_inline_ = 'try'
+    # NB. this function is not inlined right now.  backendopt.inline would
+    # need some improvements to handle this case, but it's not really an
+    # issue
 
     def exception_trace(self, frame, operationerr):
         "Trace function called upon OperationError."
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
@@ -135,7 +135,10 @@
                 r = "<Guard%d>" % index
             else:
                 r = self.repr_of_descr(descr)
-            args += ', descr=' +  r
+            if args:
+                args += ', descr=' +  r
+            else:
+                args = "descr=" + r
         if is_guard and op.getfailargs() is not None:
             fail_args = ' [' + ", ".join([self.repr_of_arg(arg)
                                           for arg in op.getfailargs()]) + ']'
diff --git a/pypy/jit/metainterp/test/test_logger.py 
b/pypy/jit/metainterp/test/test_logger.py
--- a/pypy/jit/metainterp/test/test_logger.py
+++ b/pypy/jit/metainterp/test/test_logger.py
@@ -104,6 +104,17 @@
         '''
         self.reparse(inp)
 
+    def test_guard_not_invalidated(self):
+        inp = '''
+        []
+        guard_not_invalidated(descr=descr) []
+        finish()
+        '''
+        loop = pure_parse(inp, namespace={'descr': Descr()})
+        logger = Logger(self.make_metainterp_sd())
+        output = logger.log_loop(loop, {'descr': Descr()})
+        assert 'guard_not_invalidated(descr=' in output
+
     def test_guard_w_hole(self):
         inp = '''
         [i0]
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -610,11 +610,7 @@
                 maybe_compile_and_run(state.increment_threshold, *args)
             maybe_enter_jit._always_inline_ = True
         jd._maybe_enter_jit_fn = maybe_enter_jit
-
-        def maybe_enter_from_start(*args):
-            maybe_compile_and_run(state.increment_function_threshold, *args)
-        maybe_enter_from_start._always_inline_ = True
-        jd._maybe_enter_from_start_fn = maybe_enter_from_start
+        jd._maybe_compile_and_run_fn = maybe_compile_and_run
 
     def make_driverhook_graphs(self):
         from pypy.rlib.jit import BaseJitCell
@@ -863,13 +859,26 @@
         RESULT = PORTALFUNC.RESULT
         result_kind = history.getkind(RESULT)
         ts = self.cpu.ts
+        state = jd.warmstate
+        maybe_compile_and_run = jd._maybe_compile_and_run_fn
 
         def ll_portal_runner(*args):
             start = True
             while 1:
                 try:
+                    # maybe enter from the function's start.  Note that the
+                    # 'start' variable is constant-folded away because it's
+                    # the first statement in the loop.
                     if start:
-                        jd._maybe_enter_from_start_fn(*args)
+                        maybe_compile_and_run(
+                            state.increment_function_threshold, *args)
+                    #
+                    # then run the normal portal function, i.e. the
+                    # interpreter's main loop.  It might enter the jit
+                    # via maybe_enter_jit(), which typically ends with
+                    # handle_fail() being called, which raises on the
+                    # following exceptions --- catched here, because we
+                    # want to interrupt the whole interpreter loop.
                     return support.maybe_on_top_of_llinterp(rtyper,
                                                       portal_ptr)(*args)
                 except self.ContinueRunningNormally, e:
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
@@ -320,7 +320,7 @@
                         Py_DecRef(space, arg)
             unwrapper.func = func
             unwrapper.api_func = api_function
-            unwrapper._always_inline_ = True
+            unwrapper._always_inline_ = 'try'
             return unwrapper
 
         unwrapper_catch = make_unwrapper(True)
@@ -625,7 +625,7 @@
                 pypy_debug_catch_fatal_exception()
         rffi.stackcounter.stacks_counter -= 1
         return retval
-    callable._always_inline_ = True
+    callable._always_inline_ = 'try'
     wrapper.__name__ = "wrapper for %r" % (callable, )
     return wrapper
 
diff --git a/pypy/module/cpyext/include/patchlevel.h 
b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
 #define PY_VERSION             "2.7.3"
 
 /* PyPy version as a string */
-#define PYPY_VERSION "1.9.1"
+#define PYPY_VERSION "2.0.0-beta1"
 
 /* Subversion Revision number of this file (not of the repository).
  * Empty since Mercurial migration. */
diff --git a/pypy/module/cpyext/test/test_version.py 
b/pypy/module/cpyext/test/test_version.py
--- a/pypy/module/cpyext/test/test_version.py
+++ b/pypy/module/cpyext/test/test_version.py
@@ -14,4 +14,8 @@
         """
         module = self.import_module(name='foo', init=init)
         assert module.py_version == sys.version[:5]
-        assert module.pypy_version == '%d.%d.%d' % sys.pypy_version_info[:3]
+        v = sys.pypy_version_info
+        s = '%d.%d.%d' % (v[0], v[1], v[2])
+        if v.releaselevel != 'final':
+            s += '-%s%d' % (v[3], v[4])
+        assert module.pypy_version == s
diff --git a/pypy/module/pypyjit/interp_resop.py 
b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -83,8 +83,8 @@
 
     The hook will be called as in: hook(jitdriver_name, greenkey, reason)
 
-    Where reason is the reason for abort, see documentation for 
set_compile_hook
-    for descriptions of other arguments.
+    Reason is a string, the meaning of other arguments is the same
+    as attributes on JitLoopInfo object
     """
     cache = space.fromcache(Cache)
     cache.w_abort_hook = w_hook
@@ -292,10 +292,24 @@
         return space.wrap('<JitLoopInfo %s, %d operations, starting at <%s>>' %
                           (self.jd_name, lgt, code_repr))
 
+    def descr_get_bridge_no(self, space):
+        if space.is_none(self.w_green_key):
+            return space.wrap(self.bridge_no)
+        raise OperationError(space.w_TypeError, space.wrap("not a bridge"))
+
+    def descr_get_key(self, space):
+        if space.is_none(self.w_green_key):
+            return space.newtuple([space.wrap(self.type[0]), space.wrap(
+                self.bridge_no)])
+        return space.newtuple([space.wrap(self.type[0]),
+                               space.wrap(self.loop_no)])
+
+
 @unwrap_spec(loopno=int, asmaddr=int, asmlen=int, loop_no=int,
              type=str, jd_name=str, bridge_no=int)
 def descr_new_jit_loop_info(space, w_subtype, w_greenkey, w_ops, loopno,
-                            asmaddr, asmlen, loop_no, type, jd_name, 
bridge_no):
+                            asmaddr, asmlen, loop_no, type, jd_name,
+                            bridge_no=-1):
     w_info = space.allocate_instance(W_JitLoopInfo, w_subtype)
     w_info.w_green_key = w_greenkey
     w_info.w_ops = w_ops
@@ -321,6 +335,12 @@
                                        "List of operations in this loop."),
     loop_no = interp_attrproperty('loop_no', cls=W_JitLoopInfo, doc=
                                   "Loop cardinal number"),
+    bridge_no = GetSetProperty(W_JitLoopInfo.descr_get_bridge_no,
+                               doc="bridge number (if a bridge)"),
+    type = interp_attrproperty('type', cls=W_JitLoopInfo,
+                               doc="Loop type"),
+    key = GetSetProperty(W_JitLoopInfo.descr_get_key,
+                         doc="bridge key in counters"),
     __repr__ = interp2app(W_JitLoopInfo.descr_repr),
 )
 W_JitLoopInfo.acceptable_as_base_class = False
@@ -352,7 +372,9 @@
     ll_times = jit_hooks.stats_get_loop_run_times(None)
     w_times = space.newdict()
     for i in range(len(ll_times)):
-        space.setitem(w_times, space.wrap(ll_times[i].number),
+        w_key = space.newtuple([space.wrap(ll_times[i].type),
+                                space.wrap(ll_times[i].number)])
+        space.setitem(w_times, w_key,
                       space.wrap(ll_times[i].counter))
     w_counters = space.newdict()
     for i, counter_name in enumerate(Counters.counter_names):
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py 
b/pypy/module/pypyjit/test/test_jit_hook.py
--- a/pypy/module/pypyjit/test/test_jit_hook.py
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -118,6 +118,9 @@
         assert info.greenkey[1] == 0
         assert info.greenkey[2] == False
         assert info.loop_no == 0
+        assert info.type == 'loop'
+        raises(TypeError, 'info.bridge_no')
+        assert info.key == ('loop', 0)
         assert len(info.operations) == 4
         int_add = info.operations[0]
         dmp = info.operations[1]
diff --git a/pypy/module/select/interp_select.py 
b/pypy/module/select/interp_select.py
--- a/pypy/module/select/interp_select.py
+++ b/pypy/module/select/interp_select.py
@@ -100,6 +100,41 @@
         if _c.FD_ISSET(fd, ll_list):
             reslist_w.append(list_w[i])
 
+def _call_select(space, iwtd_w, owtd_w, ewtd_w,
+                 ll_inl, ll_outl, ll_errl, ll_timeval):
+    fdlistin  = None
+    fdlistout = None
+    fdlisterr = None
+    nfds = -1
+    if ll_inl:
+        fdlistin, nfds = _build_fd_set(space, iwtd_w, ll_inl, nfds)
+    if ll_outl:
+        fdlistout, nfds = _build_fd_set(space, owtd_w, ll_outl, nfds)
+    if ll_errl:
+        fdlisterr, nfds = _build_fd_set(space, ewtd_w, ll_errl, nfds)
+
+    res = _c.select(nfds + 1, ll_inl, ll_outl, ll_errl, ll_timeval)
+
+    if res < 0:
+        errno = _c.geterrno()
+        msg = _c.socket_strerror_str(errno)
+        w_errortype = space.fromcache(Cache).w_error
+        raise OperationError(w_errortype, space.newtuple([
+            space.wrap(errno), space.wrap(msg)]))
+
+    resin_w = []
+    resout_w = []
+    reserr_w = []
+    if res > 0:
+        if fdlistin is not None:
+            _unbuild_fd_set(space, iwtd_w, fdlistin,  ll_inl,  resin_w)
+        if fdlistout is not None:
+            _unbuild_fd_set(space, owtd_w, fdlistout, ll_outl, resout_w)
+        if fdlisterr is not None:
+            _unbuild_fd_set(space, ewtd_w, fdlisterr, ll_errl, reserr_w)
+    return space.newtuple([space.newlist(resin_w),
+                           space.newlist(resout_w),
+                           space.newlist(reserr_w)])
 
 @unwrap_spec(w_timeout = WrappedDefault(None))
 def select(space, w_iwtd, w_owtd, w_ewtd, w_timeout):
@@ -128,61 +163,36 @@
     owtd_w = space.listview(w_owtd)
     ewtd_w = space.listview(w_ewtd)
 
+    if space.is_w(w_timeout, space.w_None):
+        timeout = -1.0
+    else:
+        timeout = space.float_w(w_timeout)
+
     ll_inl  = lltype.nullptr(_c.fd_set.TO)
     ll_outl = lltype.nullptr(_c.fd_set.TO)
     ll_errl = lltype.nullptr(_c.fd_set.TO)
     ll_timeval = lltype.nullptr(_c.timeval)
-    
+
     try:
-        fdlistin  = None
-        fdlistout = None
-        fdlisterr = None
-        nfds = -1
         if len(iwtd_w) > 0:
             ll_inl = lltype.malloc(_c.fd_set.TO, flavor='raw')
-            fdlistin, nfds = _build_fd_set(space, iwtd_w, ll_inl, nfds)
         if len(owtd_w) > 0:
             ll_outl = lltype.malloc(_c.fd_set.TO, flavor='raw')
-            fdlistout, nfds = _build_fd_set(space, owtd_w, ll_outl, nfds)
         if len(ewtd_w) > 0:
             ll_errl = lltype.malloc(_c.fd_set.TO, flavor='raw')
-            fdlisterr, nfds = _build_fd_set(space, ewtd_w, ll_errl, nfds)
-
-        if space.is_w(w_timeout, space.w_None):
-            timeout = -1.0
-        else:
-            timeout = space.float_w(w_timeout)
         if timeout >= 0.0:
             ll_timeval = rffi.make(_c.timeval)
             i = int(timeout)
             rffi.setintfield(ll_timeval, 'c_tv_sec', i)
             rffi.setintfield(ll_timeval, 'c_tv_usec', int((timeout-i)*1000000))
 
-        res = _c.select(nfds + 1, ll_inl, ll_outl, ll_errl, ll_timeval)
-
-        if res < 0:
-            errno = _c.geterrno()
-            msg = _c.socket_strerror_str(errno)
-            w_errortype = space.fromcache(Cache).w_error
-            raise OperationError(w_errortype, space.newtuple([
-                space.wrap(errno), space.wrap(msg)]))
-
-        resin_w = []
-        resout_w = []
-        reserr_w = []
-        if res > 0:
-            if fdlistin is not None:
-                _unbuild_fd_set(space, iwtd_w, fdlistin,  ll_inl,  resin_w)
-            if fdlistout is not None:
-                _unbuild_fd_set(space, owtd_w, fdlistout, ll_outl, resout_w)
-            if fdlisterr is not None:
-                _unbuild_fd_set(space, ewtd_w, fdlisterr, ll_errl, reserr_w)
+        # Call this as a separate helper to avoid a large piece of code
+        # in try:finally:.  Needed for calling further _always_inline_
+        # helpers like _build_fd_set().
+        return _call_select(space, iwtd_w, owtd_w, ewtd_w,
+                            ll_inl, ll_outl, ll_errl, ll_timeval)
     finally:
         if ll_timeval: lltype.free(ll_timeval, flavor='raw')
         if ll_errl:    lltype.free(ll_errl, flavor='raw')
         if ll_outl:    lltype.free(ll_outl, flavor='raw')
         if ll_inl:     lltype.free(ll_inl, flavor='raw')
-
-    return space.newtuple([space.newlist(resin_w),
-                           space.newlist(resout_w),
-                           space.newlist(reserr_w)])
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -11,7 +11,7 @@
 #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
 CPYTHON_API_VERSION        = 1013   #XXX # sync with include/modsupport.h
 
-PYPY_VERSION               = (1, 9, 1, "dev", 0)    #XXX # sync patchlevel.h
+PYPY_VERSION               = (2, 0, 0, "beta", 1)    #XXX # sync patchlevel.h
 
 if platform.name == 'msvc':
     COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -797,7 +797,7 @@
             wordshift += 1
         z._normalize()
         return z
-    rshift._always_inline_ = True # It's so fast that it's always benefitial.
+    rshift._always_inline_ = 'try' # It's so fast that it's always benefitial.
     
     @jit.elidable
     def and_(self, other):
diff --git a/pypy/rpython/lltypesystem/rffi.py 
b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -250,7 +250,7 @@
                 return cast(lltype.Unsigned, res)
         return res
     wrapper._annspecialcase_ = 'specialize:ll'
-    wrapper._always_inline_ = True
+    wrapper._always_inline_ = 'try'
     # for debugging, stick ll func ptr to that
     wrapper._ptr = funcptr
     wrapper = func_with_new_name(wrapper, name)
@@ -772,7 +772,7 @@
         """
         raw_buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
         return raw_buf, lltype.nullptr(STRTYPE)
-    alloc_buffer._always_inline_ = True # to get rid of the returned tuple
+    alloc_buffer._always_inline_ = 'try' # to get rid of the returned tuple
     alloc_buffer._annenforceargs_ = [int]
 
     # (char*, str, int, int) -> None
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
@@ -676,6 +676,10 @@
                         n += 1
     log.inlining("%d call sites instrumented" % n)
 
+def always_inline(graph):
+    return (hasattr(graph, 'func') and
+            getattr(graph.func, '_always_inline_', None))
+
 def auto_inlining(translator, threshold=None,
                   callgraph=None,
                   call_count_pred=None,
@@ -701,8 +705,7 @@
     while heap:
         weight, _, graph = heap[0]
         if not valid_weight.get(graph):
-            if hasattr(graph, 'func') and \
-                   getattr(graph.func, '_always_inline_', None):
+            if always_inline(graph):
                 weight, fixed = 0.0, True
             else:
                 weight, fixed = heuristic(graph)
@@ -710,7 +713,7 @@
             heapreplace(heap, (weight, -len(callers[graph]), graph))
             valid_weight[graph] = True
             if not fixed:
-                try_again[graph] = True
+                try_again[graph] = 'initial'
             continue
 
         if weight >= threshold:
@@ -745,8 +748,8 @@
                                            call_count_pred, cleanup=False)
                 to_cleanup[parentgraph] = True
                 res = bool(subcount)
-            except CannotInline:
-                try_again[graph] = True
+            except CannotInline, e:
+                try_again[graph] = str(e)
                 res = CannotInline
             if res is True:
                 count += subcount
@@ -762,6 +765,15 @@
                     del try_again[parentgraph]
                     heappush(heap, (0.0, -len(callers[parentgraph]), 
parentgraph))
                 valid_weight[parentgraph] = False
+
+    invalid = [(graph, msg) for graph, msg in try_again.items()
+                            if always_inline(graph) is True]
+    if invalid:
+        message = '\n'.join([
+            "%s has _always_inline_=True but inlining failed:\n\t%s" %
+            (graph, msg) for (graph, msg) in invalid])
+        raise CannotInline(message)
+
     for graph in to_cleanup:
         cleanup_graph(graph)
     return count
diff --git a/pypy/translator/backendopt/test/test_inline.py 
b/pypy/translator/backendopt/test/test_inline.py
--- a/pypy/translator/backendopt/test/test_inline.py
+++ b/pypy/translator/backendopt/test/test_inline.py
@@ -759,3 +759,23 @@
         eval_func = self.check_inline(g, f, [int, int])
         res = eval_func([10, 173])
         assert res == f(10, 173)
+
+    def test_cannot_inline_1(self):
+        from pypy.rpython.lltypesystem import lltype, rffi
+        for attr in [None, 'try', True]:
+            def h1(n):
+                return lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+            if attr is not None:
+                h1._always_inline_ = attr
+            def f(x):
+                try:
+                    return h1(x)
+                except Exception:
+                    return lltype.nullptr(rffi.INTP.TO)
+            #
+            def compile():
+                self.check_auto_inlining(f, [int])
+            if attr is True:
+                py.test.raises(CannotInline, compile)
+            else:
+                compile()    # assert does not raise
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to