Commits

Armin Rigo committed 6ce8443

Kill callback_hook. Replace it with a simpler and more explicit solution, which is to decorate
explicitly the callbacks that you want the JIT to treat specially.

Btw, another potential use of this would be to have the JIT see some function which is deep inside
@dont_look_inside code, but which causes more app-level Python code to be invoked. This can be useful,
to let the JIT see a bit more than just the app-level Python code (e.g. the wrapping of arguments).

  • Participants
  • Parent commits ad1b2b6

Comments (0)

Files changed (9)

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

         self.check_trace_count(1)
 
 
-    def test_callback_jit_merge_point(self):
-        from pypy.rlib.objectmodel import register_around_callback_hook
-        from pypy.rpython.lltypesystem import lltype, rffi
-        from pypy.translator.tool.cbuild import ExternalCompilationInfo
-        
-        callback_jit_driver = JitDriver(greens = ['name'], reds = 'auto')
-        
-        def callback_merge_point(name):
-            callback_jit_driver.jit_merge_point(name=name)
-    
-        @callback_jit_driver.inline(callback_merge_point)
-        def callback_hook(name):
-            pass
-
-        def callback(a, b):
-            if a > b:
-                return 1
-            return -1
-
-        CB_TP = rffi.CCallback([lltype.Signed, lltype.Signed], lltype.Signed)
-        eci = ExternalCompilationInfo(includes=['stdlib.h'])
-        qsort = rffi.llexternal('qsort',
-                                [rffi.VOIDP, lltype.Signed, lltype.Signed,
-                                 CB_TP], lltype.Void, compilation_info=eci)
-        ARR = rffi.CArray(lltype.Signed)
-
-        def main():
-            register_around_callback_hook(callback_hook)
-            raw = lltype.malloc(ARR, 10, flavor='raw')
-            for i in range(10):
-                raw[i] = 10 - i
-            qsort(raw, 10, rffi.sizeof(lltype.Signed), callback)
-            lltype.free(raw, flavor='raw')
-
-        self.meta_interp(main, [])
-        self.check_trace_count(1)
-
-
 class TestLLWarmspot(WarmspotTests, LLJitMixin):
     CPUClass = runner.LLGraphCPU
     type_system = 'lltype'

File pypy/module/_cffi_backend/ccallback.py

 
 STDERR = 2
 
+@jit.jit_callback("CFFI")
 def invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
     """ Callback specification.
     ffi_cif - something ffi specific, don't care
         callback.write_error_return_value(ll_res)
     if ec is not None:
         cerrno.restore_errno_from(ec)
-invoke_callback._callback_hook_ = "CFFI"

File pypy/module/pyexpat/interp_pyexpat.py

 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
 from pypy.interpreter.error import OperationError
-from pypy.rlib import rgc
+from pypy.rlib import rgc, jit
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
         post_code = ''
 
     src = py.code.Source("""
+    @jit.jit_callback('XML:%(name)s')
     def %(name)s_callback(%(first_arg)s, %(args)s):
         id = rffi.cast(lltype.Signed, %(ll_id)s)
         userdata = global_storage.get_object(id)
     """ % locals())
 
     exec str(src)
-    callback._callback_hook_ = "XML_" + name
 
     c_name = 'XML_Set' + name
     callback_type = lltype.Ptr(lltype.FuncType(
     else:
         result = 1
     return rffi.cast(rffi.INT, result)
-UnknownEncodingHandlerData_callback._callback_hook_ = None    # no jit needed
 callback_type = lltype.Ptr(lltype.FuncType(
     [rffi.VOIDP, rffi.CCHARP, XML_Encoding_Ptr], rffi.INT))
 XML_SetUnknownEncodingHandler = expat_external(

File pypy/module/pypyjit/interp_jit.py

 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
-from pypy.rlib import jit, objectmodel
+from pypy.rlib import jit
 from pypy.rlib.jit import current_trace_length, unroll_parameters
 import pypy.interpreter.pyopcode   # for side-effects
 from pypy.interpreter.error import OperationError, operationerrfmt
                                     is_being_profiled=self.is_being_profiled)
         return jumpto
 
-callback_jit_driver = JitDriver(greens = ['name'], reds = 'auto')
-
-def callback_merge_point(name):
-    callback_jit_driver.jit_merge_point(name=name)
-
-@callback_jit_driver.inline(callback_merge_point)
-def callback_hook(name):
-    pass
-
 def _get_adapted_tick_counter():
     # Normally, the tick counter is decremented by 100 for every
     # Python opcode.  Here, to better support JIT compilation of

File pypy/rlib/clibffi.py

                                    hints={'callback':True}))
 
 
+@jit.jit_callback("CLIBFFI")
 def ll_callback(ffi_cif, ll_res, ll_args, ll_userdata):
     """ Callback specification.
     ffi_cif - something ffi specific, don't care
     """
     userdata = rffi.cast(USERDATA_P, ll_userdata)
     userdata.callback(ll_args, ll_res, userdata)
-ll_callback._callback_hook_ = "CLIBFFI"
 
 class StackCheckError(ValueError):
     message = None

File pypy/rlib/jit.py

     pass
 
 
+def jit_callback(name):
+    """Use as a decorator for C callback functions, to insert a
+    jitdriver.jit_merge_point() at the start.  Only for callbacks
+    that typically invoke more app-level Python code.
+    """
+    def decorate(func):
+        from pypy.tool.sourcetools import compile2
+        #
+        def get_printable_location():
+            return name
+        jitdriver = JitDriver(get_printable_location=get_printable_location,
+                              greens=[], reds='auto', name=name)
+        #
+        args = ','.join(['a%d' % i for i in range(func.func_code.co_argcount)])
+        source = """def callback_with_jitdriver(%(args)s):
+                        jitdriver.jit_merge_point()
+                        return real_callback(%(args)s)""" % locals()
+        miniglobals = {
+            'jitdriver': jitdriver,
+            'real_callback': func,
+            }
+        exec compile2(source) in miniglobals
+        return miniglobals['callback_with_jitdriver']
+    return decorate
+
+
 # ____________________________________________________________
 # VRefs
 
             self.autoreds = True
             self.reds = []
             self.numreds = None # see warmspot.autodetect_jit_markers_redvars
-            for hook in (get_jitcell_at, set_jitcell_at, get_printable_location,
-                         confirm_enter_jit):
-                assert hook is None, "reds='auto' is not compatible with JitDriver hooks"
+            assert confirm_enter_jit is None, (
+                "reds='auto' is not compatible with confirm_enter_jit")
         else:
             if reds is not None:
                 self.reds = reds

File pypy/rlib/objectmodel.py

     llhelper(rffi.AroundFnPtr, before)
     llhelper(rffi.AroundFnPtr, after)
 
-def register_around_callback_hook(hook):
-    """ Register a hook that's called before a callback from C calls RPython.
-    Primary usage is for JIT to have 'started from' hook.
-    """
-    from pypy.rpython.lltypesystem import rffi
-    from pypy.rpython.annlowlevel import llhelper
-   
-    rffi.aroundstate.callback_hook = hook
-    llhelper(rffi.CallbackHookPtr, hook)
-
 def is_in_callback():
     from pypy.rpython.lltypesystem import rffi
     return rffi.stackcounter.stacks_counter > 1

File pypy/rpython/lltypesystem/rffi.py

 import py
 from pypy.annotation import model as annmodel
-from pypy.rpython.lltypesystem import lltype, rstr
+from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem import ll2ctypes
 from pypy.rpython.lltypesystem.llmemory import cast_ptr_to_adr
 from pypy.rpython.lltypesystem.llmemory import itemoffsetof, raw_memcopy
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rpython.tool.rfficache import platform, sizeof_c_type
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rpython.annlowlevel import llhelper, llstr
+from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.rstring import StringBuilder, UnicodeBuilder, assert_str0
 from pypy.rlib import jit
     if callbackholder is not None:
         callbackholder.callbacks[callable] = True
     args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))])
-    invoke_hook = getattr(callable, '_callback_hook_', None)
-    assert invoke_hook is None or isinstance(invoke_hook, str)
-
     source = py.code.Source(r"""
-        def inner_wrapper(%(args)s):
-            if invoke_hook is not None and aroundstate is not None:
-                callback_hook = aroundstate.callback_hook
-                if callback_hook:
-                    callback_hook(llstr(invoke_hook))
-            return callable(%(args)s)
-        inner_wrapper._never_inline_ = True
-        
         def wrapper(%(args)s):    # no *args - no GIL for mallocing the tuple
             llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
             if aroundstate is not None:
             # from now on we hold the GIL
             stackcounter.stacks_counter += 1
             try:
-                result = inner_wrapper(%(args)s)
+                result = callable(%(args)s)
             except Exception, e:
                 os.write(2,
                     "Warning: uncaught exception in callback: %%s %%s\n" %%
     miniglobals = locals().copy()
     miniglobals['Exception'] = Exception
     miniglobals['os'] = os
-    miniglobals['llstr'] = llstr
     miniglobals['we_are_translated'] = we_are_translated
     miniglobals['stackcounter'] = stackcounter
     exec source.compile() in miniglobals
 _make_wrapper_for._annspecialcase_ = 'specialize:memo'
 
 AroundFnPtr = lltype.Ptr(lltype.FuncType([], lltype.Void))
-CallbackHookPtr = lltype.Ptr(lltype.FuncType([lltype.Ptr(rstr.STR)], lltype.Void))
 
 class AroundState:
-    callback_hook = None
-    
     def _cleanup_(self):
         self.before = None        # or a regular RPython function
         self.after = None         # or a regular RPython function

File pypy/translator/goal/targetpypystandalone.py

     w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup))
     withjit = space.config.objspace.usemodules.pypyjit
 
-    if withjit:
-        from pypy.module.pypyjit.interp_jit import callback_hook
-        from pypy.rlib import objectmodel
-        objectmodel.register_around_callback_hook(callback_hook)
-
     def entry_point(argv):
         if withjit:
             from pypy.jit.backend.hlinfo import highleveljitinfo