def test_include_write_array(): A = lltype.GcArray(lltype.Signed) effects = frozenset([("array", lltype.Ptr(A))]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_fields assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)]
def test_include_write_field(): S = lltype.GcStruct("S", ("a", lltype.Signed)) effects = frozenset([("struct", lltype.Ptr(S), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) assert list(effectinfo._write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo._readonly_descrs_fields assert not effectinfo._write_descrs_arrays
def test_include_write_field(): S = lltype.GcStruct("S", ("a", lltype.Signed)) effects = frozenset([("struct", lltype.Ptr(S), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU()) assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")] assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_arrays
def test_filter_out_struct_with_void(): effects = frozenset([ ("struct", lltype.Ptr(lltype.GcStruct("x", ("a", lltype.Void))), "a") ]) effectinfo = effectinfo_from_writeanalyze(effects, None) assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_fields assert not effectinfo.write_descrs_arrays
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE, extraeffect=None, extradescr=None): """Return the calldescr that describes all calls done by 'op'. This returns a calldescr that we can put in the corresponding call operation in the calling jitcode. It gets an effectinfo describing the effect of the call: which field types it may change, whether it can force virtualizables, whether it can raise, etc. """ NON_VOID_ARGS = [x.concretetype for x in op.args[1:] if x.concretetype is not lltype.Void] RESULT = op.result.concretetype # check the number and type of arguments FUNC = op.args[0].concretetype.TO ARGS = FUNC.ARGS if NON_VOID_ARGS != [T for T in ARGS if T is not lltype.Void]: raise Exception( "in operation %r: caling a function with signature %r, " "but passing actual arguments (ignoring voids) of types %r" % (op, FUNC, NON_VOID_ARGS)) if RESULT != FUNC.RESULT: raise Exception( "in operation %r: caling a function with signature %r, " "but the actual return type is %r" % (op, FUNC, RESULT)) # ok # 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 = op.args[0].value._obj assert getattr(funcobj, 'calling_conv', 'c') == 'c', ( "%r: getcalldescr() with a non-default call ABI" % (op,)) func = getattr(funcobj, '_callable', None) elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) 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) elif op.opname == 'indirect_call': # check that we're not trying to call indirectly some # function with the special flags graphs = op.args[-1].value for graph in (graphs or ()): if not hasattr(graph, 'func'): continue error = None if hasattr(graph.func, '_elidable_function_'): error = '@jit.elidable' if hasattr(graph.func, '_jit_loop_invariant_'): error = '@jit.loop_invariant' if hasattr(graph.func, '_call_aroundstate_target_'): error = '_call_aroundstate_target_' if not error: continue raise Exception( "%r is an indirect call to a family of functions " "(or methods) that includes %r. However, the latter " "is marked %r. You need to use an indirection: replace " "it with a non-marked function/method which calls the " "marked function." % (op, graph, error)) # build the extraeffect random_effects = self.randomeffects_analyzer.analyze(op) if random_effects: extraeffect = EffectInfo.EF_RANDOM_EFFECTS # random_effects implies can_invalidate can_invalidate = random_effects or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: if self._canraise(op): extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE else: extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: extraeffect = EffectInfo.EF_CANNOT_RAISE # # check that the result is really as expected if loopinvariant: if extraeffect != EffectInfo.EF_LOOPINVARIANT: raise Exception( "in operation %r: this calls a _jit_loop_invariant_ function," " but this contradicts other sources (e.g. it can have random" " effects): EF=%s" % (op, extraeffect)) if elidable: if extraeffect not in (EffectInfo.EF_ELIDABLE_CANNOT_RAISE, EffectInfo.EF_ELIDABLE_CAN_RAISE): raise Exception( "in operation %r: this calls an _elidable_function_," " but this contradicts other sources (e.g. it can have random" " effects): EF=%s" % (op, extraeffect)) # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op, self.seen), self.cpu, extraeffect, oopspecindex, can_invalidate, call_release_gil_target, extradescr, ) # assert effectinfo is not None if elidable or loopinvariant: assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but # it can't because our analyzer is not good enough for now # (and getexecutioncontext() can't really invalidate) # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE, extraeffect=None, extradescr=None): """Return the calldescr that describes all calls done by 'op'. This returns a calldescr that we can put in the corresponding call operation in the calling jitcode. It gets an effectinfo describing the effect of the call: which field types it may change, whether it can force virtualizables, whether it can raise, etc. """ NON_VOID_ARGS = [ x.concretetype for x in op.args[1:] if x.concretetype is not lltype.Void ] RESULT = op.result.concretetype # check the number and type of arguments FUNC = op.args[0].concretetype.TO ARGS = FUNC.ARGS if NON_VOID_ARGS != [T for T in ARGS if T is not lltype.Void]: raise Exception( "in operation %r: caling a function with signature %r, " "but passing actual arguments (ignoring voids) of types %r" % (op, FUNC, NON_VOID_ARGS)) if RESULT != FUNC.RESULT: raise Exception( "in operation %r: caling a function with signature %r, " "but the actual return type is %r" % (op, FUNC, RESULT)) # ok # get the 'elidable' and 'loopinvariant' flags from the function object elidable = False loopinvariant = False call_release_gil_target = EffectInfo._NO_CALL_RELEASE_GIL_TARGET if op.opname == "direct_call": funcobj = op.args[0].value._obj assert getattr(funcobj, 'calling_conv', 'c') == 'c', ( "%r: getcalldescr() with a non-default call ABI" % (op, )) func = getattr(funcobj, '_callable', None) elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") if getattr(func, "_call_aroundstate_target_", None): tgt_func, tgt_saveerr = func._call_aroundstate_target_ tgt_func = llmemory.cast_ptr_to_adr(tgt_func) call_release_gil_target = (tgt_func, tgt_saveerr) elif op.opname == 'indirect_call': # check that we're not trying to call indirectly some # function with the special flags graphs = op.args[-1].value for graph in (graphs or ()): if not hasattr(graph, 'func'): continue error = None if hasattr(graph.func, '_elidable_function_'): error = '@jit.elidable' if hasattr(graph.func, '_jit_loop_invariant_'): error = '@jit.loop_invariant' if hasattr(graph.func, '_call_aroundstate_target_'): error = '_call_aroundstate_target_' if not error: continue raise Exception( "%r is an indirect call to a family of functions " "(or methods) that includes %r. However, the latter " "is marked %r. You need to use an indirection: replace " "it with a non-marked function/method which calls the " "marked function." % (op, graph, error)) # build the extraeffect random_effects = self.randomeffects_analyzer.analyze(op) if random_effects: extraeffect = EffectInfo.EF_RANDOM_EFFECTS # random_effects implies can_invalidate can_invalidate = random_effects or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: cr = self._canraise(op) if cr == "mem": extraeffect = EffectInfo.EF_ELIDABLE_OR_MEMORYERROR elif cr: extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE else: extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): # True or "mem" extraeffect = EffectInfo.EF_CAN_RAISE else: extraeffect = EffectInfo.EF_CANNOT_RAISE # # check that the result is really as expected if loopinvariant: if extraeffect != EffectInfo.EF_LOOPINVARIANT: raise Exception( "in operation %r: this calls a _jit_loop_invariant_ function," " but this contradicts other sources (e.g. it can have random" " effects): EF=%s" % (op, extraeffect)) if elidable: if extraeffect not in (EffectInfo.EF_ELIDABLE_CANNOT_RAISE, EffectInfo.EF_ELIDABLE_OR_MEMORYERROR, EffectInfo.EF_ELIDABLE_CAN_RAISE): raise Exception( "in operation %r: this calls an elidable function," " but this contradicts other sources (e.g. it can have random" " effects): EF=%s" % (op, extraeffect)) elif RESULT is lltype.Void: raise Exception( "in operation %r: this calls an elidable function " "but the function has no result" % (op, )) # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op, self.seen_rw), self.cpu, extraeffect, oopspecindex, can_invalidate, call_release_gil_target, extradescr, self.collect_analyzer.analyze(op, self.seen_gc), ) # assert effectinfo is not None if elidable or loopinvariant: assert (effectinfo.extraeffect < EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE) # XXX this should also say assert not can_invalidate, but # it can't because our analyzer is not good enough for now # (and getexecutioncontext() can't really invalidate) # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)
def test_filter_out_array_of_void(): effects = frozenset([("array", lltype.Ptr(lltype.GcArray(lltype.Void)))]) effectinfo = effectinfo_from_writeanalyze(effects, None) assert not effectinfo._readonly_descrs_fields assert not effectinfo._write_descrs_fields assert not effectinfo._write_descrs_arrays
def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) effectinfo = effectinfo_from_writeanalyze(effects, None) assert not effectinfo._readonly_descrs_fields assert not effectinfo._write_descrs_fields assert not effectinfo._write_descrs_arrays
def test_filter_out_struct_with_void(): effects = frozenset([("struct", lltype.Ptr(lltype.GcStruct("x", ("a", lltype.Void))), "a")]) effectinfo = effectinfo_from_writeanalyze(effects, None) assert not effectinfo._readonly_descrs_fields assert not effectinfo._write_descrs_fields assert not effectinfo._write_descrs_arrays
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE, extraeffect=None): """Return the calldescr that describes all calls done by 'op'. This returns a calldescr that we can put in the corresponding call operation in the calling jitcode. It gets an effectinfo describing the effect of the call: which field types it may change, whether it can force virtualizables, whether it can raise, etc. """ NON_VOID_ARGS = [x.concretetype for x in op.args[1:] if x.concretetype is not lltype.Void] RESULT = op.result.concretetype # check the number and type of arguments FUNC = op.args[0].concretetype.TO ARGS = FUNC.ARGS assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok # 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 = op.args[0].value._obj assert getattr(funcobj, 'calling_conv', 'c') == 'c', ( "%r: getcalldescr() with a non-default call ABI" % (op,)) func = getattr(funcobj, '_callable', None) elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) 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: extraeffect = EffectInfo.EF_RANDOM_EFFECTS # random_effects implies can_invalidate can_invalidate = random_effects or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: if self._canraise(op): extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE else: extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: extraeffect = EffectInfo.EF_CANNOT_RAISE # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, oopspecindex, can_invalidate, call_release_gil_target, ) # assert effectinfo is not None if elidable or loopinvariant: assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but # it can't because our analyzer is not good enough for now # (and getexecutioncontext() can't really invalidate) # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)
def test_filter_out_array_of_void(): effects = frozenset([("array", lltype.Ptr(lltype.GcArray(lltype.Void)))]) effectinfo = effectinfo_from_writeanalyze(effects, None) assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_fields assert not effectinfo.write_descrs_arrays
def test_filter_out_typeptr(): effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")]) effectinfo = effectinfo_from_writeanalyze(effects, None) assert not effectinfo.readonly_descrs_fields assert not effectinfo.write_descrs_fields assert not effectinfo.write_descrs_arrays