Commits

Armin Rigo committed c782efd

Change _always_inline_=True to crash if inlining fails. Use _always_inline_='try' to not crash if it fails. Fixes left and right.

Comments (0)

Files changed (7)

pypy/interpreter/astcompiler/optimize.py

 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({

pypy/interpreter/executioncontext.py

         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."

pypy/module/cpyext/api.py

                         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)
                 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
 
             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):

pypy/rpython/lltypesystem/rffi.py

                 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)
         """
         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

pypy/translator/backendopt/inline.py

                         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,
     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)
             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:
                                            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
                     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

pypy/translator/backendopt/test/test_inline.py

         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