Commits

Armin Rigo committed db015e1 Merge

hg merge default

Comments (0)

Files changed (4)

pypy/jit/codewriter/call.py

         # get the 'elidable' and 'loopinvariant' flags from the function object
         elidable = False
         loopinvariant = False
+        call_release_gil_target = llmemory.NULL
         if op.opname == "direct_call":
             funcobj = get_funcobj(op.args[0].value)
             assert getattr(funcobj, 'calling_conv', 'c') == 'c', (
             if loopinvariant:
                 assert not NON_VOID_ARGS, ("arguments not supported for "
                                            "loop-invariant function!")
+            if getattr(func, "_call_aroundstate_target_", None):
+                call_release_gil_target = func._call_aroundstate_target_
+                call_release_gil_target = llmemory.cast_ptr_to_adr(
+                    call_release_gil_target)
         # build the extraeffect
         random_effects = self.randomeffects_analyzer.analyze(op)
         if random_effects:
         #
         effectinfo = effectinfo_from_writeanalyze(
             self.readwrite_analyzer.analyze(op), self.cpu, extraeffect,
-            oopspecindex, can_invalidate)
+            oopspecindex, can_invalidate, call_release_gil_target)
         #
         assert effectinfo is not None
         if elidable or loopinvariant:

pypy/jit/codewriter/effectinfo.py

 from pypy.jit.metainterp.typesystem import deref, fieldType, arrayItem
 from pypy.rpython.lltypesystem.rclass import OBJECT
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.ootypesystem import ootype
 from pypy.translator.backendopt.graphanalyze import BoolGraphAnalyzer
 
                 write_descrs_fields, write_descrs_arrays,
                 extraeffect=EF_CAN_RAISE,
                 oopspecindex=OS_NONE,
-                can_invalidate=False):
+                can_invalidate=False,
+                call_release_gil_target=llmemory.NULL):
         key = (frozenset_or_none(readonly_descrs_fields),
                frozenset_or_none(readonly_descrs_arrays),
                frozenset_or_none(write_descrs_fields),
                extraeffect,
                oopspecindex,
                can_invalidate)
+        if call_release_gil_target:
+            key += (object(),)    # don't care about caching in this case
         if key in cls._cache:
             return cls._cache[key]
         if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
         result.extraeffect = extraeffect
         result.can_invalidate = can_invalidate
         result.oopspecindex = oopspecindex
+        result.call_release_gil_target = call_release_gil_target
         if result.check_can_raise():
             assert oopspecindex in cls._OS_CANRAISE
         cls._cache[key] = result
     def has_random_effects(self):
         return self.extraeffect >= self.EF_RANDOM_EFFECTS
 
+    def is_call_release_gil(self):
+        return bool(self.call_release_gil_target)
+
 
 def frozenset_or_none(x):
     if x is None:
 def effectinfo_from_writeanalyze(effects, cpu,
                                  extraeffect=EffectInfo.EF_CAN_RAISE,
                                  oopspecindex=EffectInfo.OS_NONE,
-                                 can_invalidate=False):
+                                 can_invalidate=False,
+                                 call_release_gil_target=llmemory.NULL):
     from pypy.translator.backendopt.writeanalyze import top_set
     if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
         readonly_descrs_fields = None
                       write_descrs_arrays,
                       extraeffect,
                       oopspecindex,
-                      can_invalidate)
+                      can_invalidate,
+                      call_release_gil_target)
 
 def consider_struct(TYPE, fieldname):
     if fieldType(TYPE, fieldname) is lltype.Void:

pypy/jit/codewriter/test/test_call.py

 import py
 from pypy.objspace.flow.model import SpaceOperation, Constant, Variable
-from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.translator.unsimplify import varoftype
 from pypy.rlib import jit
 from pypy.jit.codewriter.call import CallControl
     [op] = block.operations
     call_descr = cc.getcalldescr(op)
     assert call_descr.extrainfo.has_random_effects()
+    assert call_descr.extrainfo.is_call_release_gil() is False
+
+def test_call_release_gil():
+    from pypy.jit.backend.llgraph.runner import LLtypeCPU
+
+    T = rffi.CArrayPtr(rffi.TIME_T)
+    external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True)
+
+    # no jit.dont_look_inside in this test
+    def f():
+        return external(lltype.nullptr(T.TO))
+
+    rtyper = support.annotate(f, [])
+    jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
+    cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
+    res = cc.find_all_graphs(FakePolicy())
+
+    [llext_graph] = [x for x in res if x.func is external]
+    [block, _] = list(llext_graph.iterblocks())
+    [op] = block.operations
+    call_target = op.args[0].value._obj.graph.func._call_aroundstate_target_
+    call_target = llmemory.cast_ptr_to_adr(call_target)
+    call_descr = cc.getcalldescr(op)
+    assert call_descr.extrainfo.has_random_effects()
+    assert call_descr.extrainfo.is_call_release_gil() is True
+    assert call_descr.extrainfo.call_release_gil_target == call_target
 
 def test_random_effects_on_stacklet_switch():
     from pypy.jit.backend.llgraph.runner import LLtypeCPU

pypy/rpython/lltypesystem/rffi.py

         call_external_function._dont_inline_ = True
         call_external_function._annspecialcase_ = 'specialize:ll'
         call_external_function._gctransformer_hint_close_stack_ = True
+        call_external_function._call_aroundstate_target_ = funcptr
         call_external_function = func_with_new_name(call_external_function,
                                                     'ccall_' + name)
         # don't inline, as a hack to guarantee that no GC pointer is alive