def make_driverhook_graphs(self): from pypy.rlib.jit import BaseJitCell bk = self.rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(BaseJitCell) s_BaseJitCell_or_None = annmodel.SomeInstance(classdef, can_be_None=True) s_BaseJitCell_not_None = annmodel.SomeInstance(classdef) s_Str = annmodel.SomeString() # annhelper = MixLevelHelperAnnotator(self.translator.rtyper) for jd in self.jitdrivers_sd: jd._set_jitcell_at_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.set_jitcell_at, annmodel.s_None, s_BaseJitCell_not_None) jd._get_jitcell_at_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.get_jitcell_at, s_BaseJitCell_or_None) jd._get_printable_location_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.get_printable_location, s_Str) jd._confirm_enter_jit_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.confirm_enter_jit, annmodel.s_Bool, onlygreens=False) jd._can_never_inline_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool) jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd, annhelper, jd.jitdriver.should_unroll_one_iteration, annmodel.s_Bool) annhelper.finish()
def cutoff_alwaysraising_block(self, block): "Fix a block whose end can never be reached at run-time." # search the operation that cannot succeed can_succeed = [op for op in block.operations if op.result in self.bindings] cannot_succeed = [op for op in block.operations if op.result not in self.bindings] n = len(can_succeed) # check consistency assert can_succeed == block.operations[:n] assert cannot_succeed == block.operations[n:] assert 0 <= n < len(block.operations) # chop off the unreachable end of the block del block.operations[n+1:] s_impossible = annmodel.SomeImpossibleValue() self.bindings[block.operations[n].result] = s_impossible # insert the equivalent of 'raise AssertionError' graph = self.annotated[block] msg = "Call to %r should have raised an exception" % (getattr(graph, 'func', None),) c1 = Constant(AssertionError) c2 = Constant(AssertionError(msg)) errlink = Link([c1, c2], graph.exceptblock) block.recloseblock(errlink, *block.exits) # record new link to make the transformation idempotent self.links_followed[errlink] = True # fix the annotation of the exceptblock.inputargs etype, evalue = graph.exceptblock.inputargs s_type = annmodel.SomeObject() s_type.knowntype = type s_type.is_type_of = [evalue] s_value = annmodel.SomeInstance(self.bookkeeper.getuniqueclassdef(Exception)) self.setbinding(etype, s_type) self.setbinding(evalue, s_value) # make sure the bookkeeper knows about AssertionError self.bookkeeper.getuniqueclassdef(AssertionError)
def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc if s_pbc.isNone(): raise TyperError("unsupported: variable of type " "bound-method-object or None") mdescs = s_pbc.descriptions.keys() methodname = mdescs[0].name classdef = mdescs[0].selfclassdef flags = mdescs[0].flags for mdesc in mdescs[1:]: if mdesc.name != methodname: raise TyperError("cannot find a unique name under which the " "methods can be found: %r" % (mdescs, )) if mdesc.flags != flags: raise TyperError("inconsistent 'flags': %r versus %r" % (mdesc.flags, flags)) classdef = classdef.commonbase(mdesc.selfclassdef) if classdef is None: raise TyperError("mixing methods coming from instances of " "classes with no common base: %r" % (mdescs, )) self.methodname = methodname self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) self.lowleveltype = self.r_im_self.lowleveltype
def default_specialize(funcdesc, args_s): # first flatten the *args args_s, key, builder = flatten_star_args(funcdesc, args_s) # two versions: a regular one and one for instances with 'access_directly' jit_look_inside = getattr(funcdesc.pyobj, '_jit_look_inside_', True) # change args_s in place, "official" interface access_directly = False for i, s_obj in enumerate(args_s): if (isinstance(s_obj, annmodel.SomeInstance) and 'access_directly' in s_obj.flags): if jit_look_inside: access_directly = True key = (AccessDirect, key) break else: new_flags = s_obj.flags.copy() del new_flags['access_directly'] new_s_obj = annmodel.SomeInstance(s_obj.classdef, s_obj.can_be_None, flags=new_flags) args_s[i] = new_s_obj # done graph = funcdesc.cachedgraph(key, builder=builder) if access_directly: graph.access_directly = True return graph
def create_instantiate_function(annotator, classdef): # build the graph of a function that looks like # # def my_instantiate(): # return instantiate(cls) # if hasattr(classdef, 'my_instantiate_graph'): return v = Variable() block = Block([]) block.operations.append(SpaceOperation('instantiate1', [], v)) name = valid_identifier('instantiate_'+classdef.name) graph = FunctionGraph(name, block) block.closeblock(Link([v], graph.returnblock)) annotator.setbinding(v, annmodel.SomeInstance(classdef)) annotator.annotated[block] = graph # force the result to be converted to a generic OBJECTPTR generalizedresult = annmodel.SomeInstance(classdef=None) annotator.setbinding(graph.getreturnvar(), generalizedresult) classdef.my_instantiate_graph = graph annotator.translator.graphs.append(graph)
def make_driverhook_graphs(self): from pypy.rlib.jit import BaseJitCell bk = self.rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(BaseJitCell) s_BaseJitCell_or_None = annmodel.SomeInstance(classdef, can_be_None=True) s_BaseJitCell_not_None = annmodel.SomeInstance(classdef) s_Str = annmodel.SomeString() # annhelper = MixLevelHelperAnnotator(self.translator.rtyper) self.set_jitcell_at_ptr = self._make_hook_graph( annhelper, self.jitdriver.set_jitcell_at, annmodel.s_None, s_BaseJitCell_not_None) self.get_jitcell_at_ptr = self._make_hook_graph( annhelper, self.jitdriver.get_jitcell_at, s_BaseJitCell_or_None) self.can_inline_ptr = self._make_hook_graph(annhelper, self.jitdriver.can_inline, annmodel.s_Bool) self.get_printable_location_ptr = self._make_hook_graph( annhelper, self.jitdriver.get_printable_location, s_Str) annhelper.finish()
def compute_result_annotation(self, s_x, **kwds_s): from pypy.annotation import model as annmodel s_x = annmodel.not_const(s_x) if 's_access_directly' in kwds_s: if isinstance(s_x, annmodel.SomeInstance): from pypy.objspace.flow.model import Constant classdesc = s_x.classdef.classdesc virtualizable = classdesc.read_attribute( '_virtualizable_', Constant(False)).value if virtualizable: flags = s_x.flags.copy() flags['access_directly'] = True s_x = annmodel.SomeInstance(s_x.classdef, s_x.can_be_None, flags) return s_x
def compute_result_annotation(self, s_x, **kwds_s): from pypy.annotation import model as annmodel s_x = annmodel.not_const(s_x) access_directly = 's_access_directly' in kwds_s fresh_virtualizable = 's_fresh_virtualizable' in kwds_s if access_directly or fresh_virtualizable: assert access_directly, "lone fresh_virtualizable hint" if isinstance(s_x, annmodel.SomeInstance): from pypy.objspace.flow.model import Constant classdesc = s_x.classdef.classdesc virtualizable = classdesc.read_attribute( '_virtualizable2_', Constant(None)).value if virtualizable is not None: flags = s_x.flags.copy() flags['access_directly'] = True if fresh_virtualizable: flags['fresh_virtualizable'] = True s_x = annmodel.SomeInstance(s_x.classdef, s_x.can_be_None, flags) return s_x
def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc if s_pbc.isNone(): raise TyperError("unsupported: variable of type " "bound-method-object or None") mdescs = s_pbc.descriptions.keys() methodname = mdescs[0].name classdef = mdescs[0].selfclassdef flags = mdescs[0].flags for mdesc in mdescs[1:]: if mdesc.name != methodname: raise TyperError("cannot find a unique name under which the " "methods can be found: %r" % (mdescs, )) if mdesc.flags != flags: raise TyperError("inconsistent 'flags': %r versus %r" % (mdesc.flags, flags)) classdef = classdef.commonbase(mdesc.selfclassdef) if classdef is None: raise TyperError("mixing methods coming from instances of " "classes with no common base: %r" % (mdescs, )) self.methodname = methodname # for ootype, the right thing to do is to always keep the most precise # type of the instance, while for lltype we want to cast it to the # type where the method is actually defined. See also # test_rclass.test_method_specialized_with_subclass and # rtyper.attach_methods_to_subclasses if self.rtyper.type_system.name == 'ootypesystem': self.classdef = classdef else: self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) self.lowleveltype = self.r_im_self.lowleveltype
def compute_result_annotation(self, s_Class, s_ptr): assert s_Class.is_constant() classdef = self.bookkeeper.getuniqueclassdef(s_Class.const) return annmodel.SomeInstance(classdef, can_be_None=True)
def s_r_instanceof(self, cls, can_be_None=True, check_never_seen=True): classdesc = self.rtyper.annotator.bookkeeper.getdesc(cls) classdef = classdesc.getuniqueclassdef() s_instance = annmodel.SomeInstance(classdef, can_be_None) r_instance = self.getdelayedrepr(s_instance, check_never_seen) return s_instance, r_instance
def __init__(self, translator): from pypy.rpython.memory.gc.base import choose_gc_from_config super(FrameworkGCTransformer, self).__init__(translator, inline=True) if hasattr(self, 'GC_PARAMS'): # for tests: the GC choice can be specified as class attributes from pypy.rpython.memory.gc.marksweep import MarkSweepGC GCClass = getattr(self, 'GCClass', MarkSweepGC) GC_PARAMS = self.GC_PARAMS else: # for regular translation: pick the GC from the config GCClass, GC_PARAMS = choose_gc_from_config(translator.config) self.layoutbuilder = TransformerLayoutBuilder(self) self.get_type_id = self.layoutbuilder.get_type_id # set up dummy a table, to be overwritten with the real one in finish() type_info_table = lltype._ptr( lltype.Ptr(gctypelayout.GCData.TYPE_INFO_TABLE), "delayed!type_info_table", solid=True) gcdata = gctypelayout.GCData(type_info_table) # initialize the following two fields with a random non-NULL address, # to make the annotator happy. The fields are patched in finish() # to point to a real array. foo = lltype.malloc(lltype.FixedSizeArray(llmemory.Address, 1), immortal=True, zero=True) a_random_address = llmemory.cast_ptr_to_adr(foo) gcdata.static_root_start = a_random_address # patched in finish() gcdata.static_root_nongcend = a_random_address # patched in finish() gcdata.static_root_end = a_random_address # patched in finish() self.gcdata = gcdata self.malloc_fnptr_cache = {} gcdata.gc = GCClass(**GC_PARAMS) root_walker = self.build_root_walker() gcdata.set_query_functions(gcdata.gc) gcdata.gc.set_root_walker(root_walker) self.num_pushs = 0 self.write_barrier_calls = 0 def frameworkgc_setup(): # run-time initialization code root_walker.setup_root_walker() gcdata.gc.setup() bk = self.translator.annotator.bookkeeper # the point of this little dance is to not annotate # self.gcdata.static_root_xyz as constants. XXX is it still needed?? data_classdef = bk.getuniqueclassdef(gctypelayout.GCData) data_classdef.generalize_attr( 'static_root_start', annmodel.SomeAddress()) data_classdef.generalize_attr( 'static_root_nongcend', annmodel.SomeAddress()) data_classdef.generalize_attr( 'static_root_end', annmodel.SomeAddress()) annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) def getfn(ll_function, args_s, s_result, inline=False, minimal_transform=True): graph = annhelper.getgraph(ll_function, args_s, s_result) if minimal_transform: self.need_minimal_transform(graph) if inline: self.graphs_to_inline[graph] = True return annhelper.graph2const(graph) self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [], annmodel.s_None) if root_walker.need_root_stack: self.incr_stack_ptr = getfn(root_walker.incr_stack, [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) self.decr_stack_ptr = getfn(root_walker.decr_stack, [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) else: self.incr_stack_ptr = None self.decr_stack_ptr = None self.weakref_deref_ptr = self.inittime_helper( ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address) classdef = bk.getuniqueclassdef(GCClass) s_gc = annmodel.SomeInstance(classdef) s_gcref = annmodel.SomePtr(llmemory.GCREF) malloc_fixedsize_clear_meth = GCClass.malloc_fixedsize_clear.im_func self.malloc_fixedsize_clear_ptr = getfn( malloc_fixedsize_clear_meth, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) if hasattr(GCClass, 'malloc_fixedsize'): malloc_fixedsize_meth = GCClass.malloc_fixedsize.im_func self.malloc_fixedsize_ptr = getfn( malloc_fixedsize_meth, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) else: malloc_fixedsize_meth = None self.malloc_fixedsize_ptr = self.malloc_fixedsize_clear_ptr ## self.malloc_varsize_ptr = getfn( ## GCClass.malloc_varsize.im_func, ## [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] ## + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) self.malloc_varsize_clear_ptr = getfn( GCClass.malloc_varsize_clear.im_func, [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) self.collect_ptr = getfn(GCClass.collect.im_func, [s_gc], annmodel.s_None) self.can_move_ptr = getfn(GCClass.can_move.im_func, [s_gc, annmodel.SomeAddress()], annmodel.SomeBool()) # in some GCs we can inline the common case of # malloc_fixedsize(typeid, size, True, False, False) if getattr(GCClass, 'inline_simple_malloc', False): # make a copy of this function so that it gets annotated # independently and the constants are folded inside if malloc_fixedsize_meth is None: malloc_fast_meth = malloc_fixedsize_clear_meth self.malloc_fast_is_clearing = True else: malloc_fast_meth = malloc_fixedsize_meth self.malloc_fast_is_clearing = False malloc_fast = func_with_new_name( malloc_fast_meth, "malloc_fast") s_False = annmodel.SomeBool(); s_False.const = False s_True = annmodel.SomeBool(); s_True .const = True self.malloc_fast_ptr = getfn( malloc_fast, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), s_True, s_False, s_False], s_gcref, inline = True) else: self.malloc_fast_ptr = None # in some GCs we can also inline the common case of # malloc_varsize(typeid, length, (3 constant sizes), True, False) if getattr(GCClass, 'inline_simple_malloc_varsize', False): # make a copy of this function so that it gets annotated # independently and the constants are folded inside malloc_varsize_clear_fast = func_with_new_name( GCClass.malloc_varsize_clear.im_func, "malloc_varsize_clear_fast") s_False = annmodel.SomeBool(); s_False.const = False s_True = annmodel.SomeBool(); s_True .const = True self.malloc_varsize_clear_fast_ptr = getfn( malloc_varsize_clear_fast, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), s_True, s_False], s_gcref, inline = True) else: self.malloc_varsize_clear_fast_ptr = None if getattr(GCClass, 'malloc_varsize_nonmovable', False): malloc_nonmovable = func_with_new_name( GCClass.malloc_varsize_nonmovable.im_func, "malloc_varsize_nonmovable") self.malloc_varsize_nonmovable_ptr = getfn( malloc_nonmovable, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True)], s_gcref) else: self.malloc_varsize_nonmovable_ptr = None if getattr(GCClass, 'malloc_varsize_resizable', False): malloc_resizable = func_with_new_name( GCClass.malloc_varsize_resizable.im_func, "malloc_varsize_resizable") self.malloc_varsize_resizable_ptr = getfn( malloc_resizable, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True)], s_gcref) else: self.malloc_varsize_resizable_ptr = None if getattr(GCClass, 'realloc', False): self.realloc_ptr = getfn( GCClass.realloc.im_func, [s_gc, s_gcref] + [annmodel.SomeInteger(nonneg=True)] * 4 + [annmodel.SomeBool()], s_gcref) if GCClass.moving_gc: self.id_ptr = getfn(GCClass.id.im_func, [s_gc, s_gcref], annmodel.SomeInteger(), inline = False, minimal_transform = False) else: self.id_ptr = None self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func, [s_gc, annmodel.SomeInteger(nonneg=True)], annmodel.s_None) if GCClass.needs_write_barrier: self.write_barrier_ptr = getfn(GCClass.write_barrier.im_func, [s_gc, annmodel.SomeAddress(), annmodel.SomeAddress()], annmodel.s_None, inline=True) else: self.write_barrier_ptr = None self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], annmodel.SomeInteger()) # experimental gc_x_* operations s_x_pool = annmodel.SomePtr(marksweep.X_POOL_PTR) s_x_clone = annmodel.SomePtr(marksweep.X_CLONE_PTR) # the x_*() methods use some regular mallocs that must be # transformed in the normal way self.x_swap_pool_ptr = getfn(GCClass.x_swap_pool.im_func, [s_gc, s_x_pool], s_x_pool, minimal_transform = False) self.x_clone_ptr = getfn(GCClass.x_clone.im_func, [s_gc, s_x_clone], annmodel.s_None, minimal_transform = False) # thread support if translator.config.translation.thread: if not hasattr(root_walker, "need_thread_support"): raise Exception("%s does not support threads" % ( root_walker.__class__.__name__,)) root_walker.need_thread_support() self.thread_prepare_ptr = getfn(root_walker.thread_prepare, [], annmodel.s_None) self.thread_run_ptr = getfn(root_walker.thread_run, [], annmodel.s_None, inline=True) self.thread_die_ptr = getfn(root_walker.thread_die, [], annmodel.s_None) annhelper.finish() # at this point, annotate all mix-level helpers annhelper.backend_optimize() self.collect_analyzer = CollectAnalyzer(self.translator) self.collect_analyzer.analyze_all() s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass) r_gc = self.translator.rtyper.getrepr(s_gc) self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc) self.malloc_zero_filled = GCClass.malloc_zero_filled HDR = self._gc_HDR = self.gcdata.gc.gcheaderbuilder.HDR self._gc_fields = fields = [] for fldname in HDR._names: FLDTYPE = getattr(HDR, fldname) fields.append(('_' + fldname, FLDTYPE))
def method_get(self, s_key): assert isinstance(s_key, annmodel.SomeInstance) assert s_key.classdef.issubclass(self.keyclassdef) return annmodel.SomeInstance(self.valueclassdef, can_be_None=True)
def method_get(self, s_key): return annmodel.SomeInstance(self.valueclassdef, can_be_None=True)
def method_get(self, s_key): assert isinstance(s_key, annmodel.SomeString) return annmodel.SomeInstance(self.valueclassdef, can_be_None=True)