Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r66817:2c08ebdc17ae Date: 2013-09-05 22:42 +0200 http://bitbucket.org/pypy/pypy/changeset/2c08ebdc17ae/
Log: merge heads diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -77,12 +77,12 @@ raise NotImplementedError("only for interp-level user subclasses " "from typedef.py") - def getname(self, space, default='?'): + def getname(self, space): try: return space.str_w(space.getattr(self, space.wrap('__name__'))) except OperationError, e: if e.match(space, space.w_TypeError) or e.match(space, space.w_AttributeError): - return default + return '?' raise def getaddrstring(self, space): diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -482,17 +482,16 @@ space.abstract_isinstance_w(w_firstarg, self.w_class)): pass # ok else: - clsdescr = self.w_class.getname(space, "") - if clsdescr: + clsdescr = self.w_class.getname(space) + if clsdescr and clsdescr != '?': clsdescr += " instance" else: clsdescr = "instance" if w_firstarg is None: instdescr = "nothing" else: - instname = space.abstract_getclass(w_firstarg).getname(space, - "") - if instname: + instname = space.abstract_getclass(w_firstarg).getname(space) + if instname and instname != '?': instdescr = instname + " instance" else: instdescr = "instance" diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -128,7 +128,7 @@ def type(self, obj): class Type: - def getname(self, space, default='?'): + def getname(self, space): return type(obj).__name__ return Type() diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -175,8 +175,8 @@ state = '; dead' else: typename = space.type(w_obj).getname(space) - objname = w_obj.getname(space, '') - if objname: + objname = w_obj.getname(space) + if objname and objname != '?': state = "; to '%s' (%s)" % (typename, objname) else: state = "; to '%s'" % (typename,) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -597,8 +597,8 @@ if num1 != num2: lt = num1 # if obj1 is a number, it is Lower Than obj2 else: - name1 = w_typ1.getname(space, "") - name2 = w_typ2.getname(space, "") + name1 = w_typ1.getname(space) + name2 = w_typ2.getname(space) if name1 != name2: lt = name1 < name2 else: diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -494,6 +494,12 @@ else: return w_self.name + def getname(w_self, space): + name = w_self.name + if name is None: + name = '?' + return name + def add_subclass(w_self, w_subclass): space = w_self.space if not space.config.translation.rweakref: diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -29,6 +29,7 @@ from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi from rpython.jit.backend.arm import callbuilder +from rpython.rtyper.lltypesystem.lloperation import llop class AssemblerARM(ResOpAssembler): @@ -1488,7 +1489,9 @@ def not_implemented(msg): - os.write(2, '[ARM/asm] %s\n' % msg) + msg = '[ARM/asm] %s\n' % msg + if we_are_translated(): + llop.debug_print(lltype.Void, msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py --- a/rpython/jit/backend/llsupport/regalloc.py +++ b/rpython/jit/backend/llsupport/regalloc.py @@ -2,6 +2,8 @@ from rpython.jit.metainterp.history import Const, Box, REF, JitCellToken from rpython.rlib.objectmodel import we_are_translated, specialize from rpython.jit.metainterp.resoperation import rop +from rpython.rtyper.lltypesystem import lltype +from rpython.rtyper.lltypesystem.lloperation import llop try: from collections import OrderedDict @@ -753,5 +755,7 @@ def not_implemented(msg): - os.write(2, '[llsupport/regalloc] %s\n' % msg) + msg = '[llsupport/regalloc] %s\n' % msg + if we_are_translated(): + llop.debug_print(lltype.Void, msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -434,6 +434,7 @@ else: self.wb_slowpath[withcards + 2 * withfloats] = rawstart + @rgc.no_release_gil def assemble_loop(self, logger, loopname, inputargs, operations, looptoken, log): '''adds the following attributes to looptoken: @@ -513,6 +514,7 @@ return AsmInfo(ops_offset, rawstart + looppos, size_excluding_failure_stuff - looppos) + @rgc.no_release_gil def assemble_bridge(self, logger, faildescr, inputargs, operations, original_loop_token, log): if not we_are_translated(): @@ -2388,7 +2390,9 @@ return AddressLoc(ImmedLoc(addr), imm0, 0, 0) def not_implemented(msg): - os.write(2, '[x86/asm] %s\n' % msg) + msg = '[x86/asm] %s\n' % msg + if we_are_translated(): + llop.debug_print(lltype.Void, msg) raise NotImplementedError(msg) cond_call_register_arguments = [edi, esi, edx, ecx] diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -28,6 +28,7 @@ from rpython.rlib.rarithmetic import r_longlong, r_uint from rpython.rtyper.annlowlevel import cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi, rstr +from rpython.rtyper.lltypesystem.lloperation import llop class X86RegisterManager(RegisterManager): @@ -1375,7 +1376,9 @@ return base_ofs + WORD * (position + JITFRAME_FIXED_SIZE) def not_implemented(msg): - os.write(2, '[x86/regalloc] %s\n' % msg) + msg = '[x86/regalloc] %s\n' % msg + if we_are_translated(): + llop.debug_print(lltype.Void, msg) raise NotImplementedError(msg) # xxx hack: set a default value for TargetToken._ll_loop_code. diff --git a/rpython/jit/backend/x86/runner.py b/rpython/jit/backend/x86/runner.py --- a/rpython/jit/backend/x86/runner.py +++ b/rpython/jit/backend/x86/runner.py @@ -1,6 +1,7 @@ import py from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rlib.jit_hooks import LOOP_RUN_CONTAINER +from rpython.rlib import rgc from rpython.jit.backend.x86.assembler import Assembler386 from rpython.jit.backend.x86.regalloc import gpr_reg_mgr_cls, xmm_reg_mgr_cls from rpython.jit.backend.x86.profagent import ProfileAgent @@ -63,10 +64,12 @@ assert self.assembler is not None return RegAlloc(self.assembler, False) + @rgc.no_release_gil def setup_once(self): self.profile_agent.startup() self.assembler.setup_once() + @rgc.no_release_gil def finish_once(self): self.assembler.finish_once() self.profile_agent.shutdown() diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -262,7 +262,11 @@ keepalive_until_here(newp) return newp - +def no_release_gil(func): + func._dont_inline_ = True + func._no_release_gil_ = True + return func + def no_collect(func): func._dont_inline_ = True func._gc_no_collect_ = True diff --git a/rpython/translator/backendopt/all.py b/rpython/translator/backendopt/all.py --- a/rpython/translator/backendopt/all.py +++ b/rpython/translator/backendopt/all.py @@ -10,6 +10,7 @@ from rpython.translator.backendopt.removeassert import remove_asserts from rpython.translator.backendopt.support import log from rpython.translator.backendopt.storesink import storesink_graph +from rpython.translator.backendopt import gilanalysis from rpython.flowspace.model import checkgraph INLINE_THRESHOLD_FOR_TEST = 33 @@ -138,6 +139,9 @@ for graph in graphs: checkgraph(graph) + gilanalysis.analyze(graphs, translator) + + def constfold(config, graphs): if config.constfold: for graph in graphs: diff --git a/rpython/translator/backendopt/gilanalysis.py b/rpython/translator/backendopt/gilanalysis.py new file mode 100644 --- /dev/null +++ b/rpython/translator/backendopt/gilanalysis.py @@ -0,0 +1,60 @@ +from rpython.translator.backendopt import graphanalyze + +# This is not an optimization. It checks for possible releases of the +# GIL in all graphs starting from rgc.no_release_gil. + + +class GilAnalyzer(graphanalyze.BoolGraphAnalyzer): + + def analyze_direct_call(self, graph, seen=None): + try: + func = graph.func + except AttributeError: + pass + else: + if getattr(func, '_gctransformer_hint_close_stack_', False): + return True + if getattr(func, '_transaction_break_', False): + return True + + return graphanalyze.BoolGraphAnalyzer.analyze_direct_call( + self, graph, seen) + + def analyze_external_call(self, op, seen=None): + funcobj = op.args[0].value._obj + if getattr(funcobj, 'transactionsafe', False): + return False + else: + return False + + def analyze_instantiate_call(self, seen=None): + return False + + def analyze_simple_operation(self, op, graphinfo): + return False + +def analyze(graphs, translator): + gilanalyzer = GilAnalyzer(translator) + for graph in graphs: + func = getattr(graph, 'func', None) + if func and getattr(func, '_no_release_gil_', False): + if gilanalyzer.analyze_direct_call(graph): + # 'no_release_gil' function can release the gil + import cStringIO + err = cStringIO.StringIO() + import sys + prev = sys.stdout + try: + sys.stdout = err + ca = GilAnalyzer(translator) + ca.verbose = True + ca.analyze_direct_call(graph) # print the "traceback" here + sys.stdout = prev + except: + sys.stdout = prev + # ^^^ for the dump of which operation in which graph actually + # causes it to return True + raise Exception("'no_release_gil' function can release the GIL:" + " %s\n%s" % (func, err.getvalue())) + + diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py --- a/rpython/translator/backendopt/graphanalyze.py +++ b/rpython/translator/backendopt/graphanalyze.py @@ -1,6 +1,7 @@ from rpython.rtyper.lltypesystem.lltype import DelayedPointer from rpython.translator.simplify import get_graph from rpython.tool.algo.unionfind import UnionFind +from rpython.rtyper.lltypesystem import rclass class GraphAnalyzer(object): @@ -67,6 +68,9 @@ result, self.analyze_direct_call(graph, seen)) return result + def analyze_instantiate_call(self, seen=None): + return self.top_result() + def analyze_link(self, graph, link): return self.bottom_result() @@ -75,7 +79,7 @@ def compute_graph_info(self, graph): return None - def analyze(self, op, seen=None, graphinfo=None): + def analyze(self, op, seen=None, graphinfo=None, block=None): if op.opname == "direct_call": graph = get_graph(op.args[0], self.translator) if graph is None: @@ -90,6 +94,18 @@ elif op.opname == "indirect_call": graphs = op.args[-1].value if graphs is None: + if block is not None: + v_func = op.args[0] + for op1 in block.operations: + if (v_func is op1.result and + op1.opname == 'getfield' and + op1.args[0].concretetype == rclass.CLASSTYPE and + op1.args[1].value == 'instantiate'): + x = self.analyze_instantiate_call(seen) + if self.verbose and x: + self.dump_info('analyze_instantiate(%s): %r' % ( + graphs, x)) + return x if self.verbose: self.dump_info('%s to unknown' % (op,)) return self.top_result() @@ -127,7 +143,7 @@ for op in block.operations: result = self.add_to_result( result, - self.analyze(op, seen, graphinfo) + self.analyze(op, seen, graphinfo, block=block) ) if self.is_top_result(result): break @@ -161,7 +177,7 @@ graphs = self.translator.graphs for graph in graphs: for block, op in graph.iterblockops(): - self.analyze(op) + self.analyze(op, block=block) class Dependency(object): diff --git a/rpython/translator/backendopt/test/test_gilanalysis.py b/rpython/translator/backendopt/test/test_gilanalysis.py new file mode 100644 --- /dev/null +++ b/rpython/translator/backendopt/test/test_gilanalysis.py @@ -0,0 +1,80 @@ +import py + +from rpython.annotator.listdef import s_list_of_strings +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.translator.backendopt import gilanalysis +from rpython.memory.gctransform.test.test_transform import rtype +from rpython.translator.translator import graphof + +def test_canrelease_external(): + for ths in ['auto', True, False]: + for sbxs in [True, False]: + fext = rffi.llexternal('fext2', [], lltype.Void, + threadsafe=ths, sandboxsafe=sbxs) + def g(): + fext() + t = rtype(g, []) + gg = graphof(t, g) + + releases = (ths == 'auto' and not sbxs) or ths is True + assert releases == gilanalysis.GilAnalyzer(t).analyze_direct_call(gg) + +def test_canrelease_instantiate(): + class O: + pass + class A(O): + pass + class B(O): + pass + + classes = [A, B] + def g(i): + classes[i]() + + t = rtype(g, [int]) + gg = graphof(t, g) + assert not gilanalysis.GilAnalyzer(t).analyze_direct_call(gg) + + + +def test_no_release_gil(): + from rpython.rlib import rgc + + @rgc.no_release_gil + def g(): + return 1 + + assert g._dont_inline_ + assert g._no_release_gil_ + + def entrypoint(argv): + return g() + 2 + + t = rtype(entrypoint, [s_list_of_strings]) + gilanalysis.analyze(t.graphs, t) + + + +def test_no_release_gil_detect(gc="minimark"): + from rpython.rlib import rgc + + fext1 = rffi.llexternal('fext1', [], lltype.Void, threadsafe=True) + @rgc.no_release_gil + def g(): + fext1() + return 1 + + assert g._dont_inline_ + assert g._no_release_gil_ + + def entrypoint(argv): + return g() + 2 + + t = rtype(entrypoint, [s_list_of_strings]) + f = py.test.raises(Exception, gilanalysis.analyze, t.graphs, t) + expected = "'no_release_gil' function can release the GIL: <function g at " + assert str(f.value).startswith(expected) + + + + _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit