def compute_at_fixpoint(self): # getbookkeeper() needs to work during this function, so provide # one with a dummy position self.enter(None) try: def call_sites(): newblocks = self.annotator.added_blocks if newblocks is None: newblocks = self.annotator.annotated # all of them annotation = self.annotator.annotation for block in newblocks: for op in block.operations: if op.opname in ('simple_call', 'call_args'): yield op # some blocks are partially annotated if annotation(op.result) is None: break # ignore the unannotated part for call_op in call_sites(): self.consider_call_site(call_op) for pbc, args_s in self.emulated_pbc_calls.itervalues(): args = simple_args(args_s) self.consider_call_site_for_pbc(pbc, args, s_ImpossibleValue, None) self.emulated_pbc_calls = {} finally: self.leave()
def emulate_pbc_call(self, unique_key, pbc, args_s, replace=[], callback=None): emulate_enter = not hasattr(self, 'position_key') if emulate_enter: self.enter(None) try: emulated_pbc_calls = self.emulated_pbc_calls prev = [unique_key] prev.extend(replace) for other_key in prev: if other_key in emulated_pbc_calls: del emulated_pbc_calls[other_key] emulated_pbc_calls[unique_key] = pbc, args_s args = simple_args(args_s) if callback is None: emulated = True else: emulated = callback return self.pbc_call(pbc, args, emulated=emulated) finally: if emulate_enter: self.leave()
def compute_at_fixpoint(self): # getbookkeeper() needs to work during this function, so provide # one with a dummy position self.enter(None) try: def call_sites(): newblocks = self.annotator.added_blocks if newblocks is None: newblocks = self.annotator.annotated # all of them annotation = self.annotator.annotation for block in newblocks: for op in block.operations: if op.opname in ('simple_call', 'call_args'): yield op # some blocks are partially annotated if annotation(op.result) is None: break # ignore the unannotated part for call_op in call_sites(): self.consider_call_site(call_op) for pbc, args_s in self.emulated_pbc_calls.itervalues(): args = simple_args(args_s) pbc.consider_call_site(args, s_ImpossibleValue, None) self.emulated_pbc_calls = {} finally: self.leave()
def get_concrete_llfn(self, s_pbc, args_s, op): bk = self.rtyper.annotator.bookkeeper funcdesc, = s_pbc.descriptions args = simple_args(args_s) with bk.at_position(None): graph = funcdesc.get_graph(args, op) llfn = self.rtyper.getcallable(graph) return inputconst(typeOf(llfn), llfn)
def get_concrete_llfn(self, s_pbc, args_s, op): bk = self.rtyper.annotator.bookkeeper funcdesc, = s_pbc.descriptions with bk.at_position(None): argspec = simple_args(args_s) graph = funcdesc.get_graph(argspec, op) llfn = self.rtyper.getcallable(graph) return inputconst(typeOf(llfn), llfn)
def compute_at_fixpoint(self): # getbookkeeper() needs to work during this function, so provide # one with a dummy position with self.at_position(None): for call_op in self.annotator.call_sites(): self.consider_call_site(call_op) for pbc, args_s in self.emulated_pbc_calls.itervalues(): args = simple_args(args_s) pbc.consider_call_site(args, s_ImpossibleValue, None) self.emulated_pbc_calls = {}
def get_concrete_llfn(self, s_pbc, args_s, op): bk = self.rtyper.annotator.bookkeeper descs = list(s_pbc.descriptions) vfcs = description.FunctionDesc.variant_for_call_site args = simple_args(args_s) shape, index = vfcs(bk, self.callfamily, descs, args, op) funcdesc, = descs row_of_one_graph = self.callfamily.calltables[shape][index] graph = row_of_one_graph[funcdesc] llfn = self.rtyper.getcallable(graph) return inputconst(lltype.typeOf(llfn), llfn)
def get_concrete_llfn(self, s_pbc, args_s, op): bk = self.rtyper.annotator.bookkeeper descs = list(s_pbc.descriptions) vfcs = description.FunctionDesc.variant_for_call_site args = simple_args(args_s) shape, index = vfcs(bk, self.callfamily, descs, args, op) funcdesc, = descs row_of_one_graph = self.callfamily.calltables[shape][index] graph = row_of_one_graph[funcdesc] llfn = self.rtyper.getcallable(graph) return inputconst(typeOf(llfn), llfn)
def get_call_parameters(self, args_s): args = simple_args(args_s) inputcells = self.parse_arguments(args) graph = self.specialize(inputcells) assert isinstance(graph, FunctionGraph) # if that graph has a different signature, we need to re-parse # the arguments. # recreate the args object because inputcells may have been changed new_args = args.unmatch_signature(self.signature, inputcells) inputcells = self.parse_arguments(new_args, graph) signature = getattr(self.pyobj, "_signature_", None) if signature: s_result = finish_type(signature[1], self.bookkeeper, self.pyobj) if s_result is not None: self.bookkeeper.annotator.addpendingblock(graph, graph.returnblock, [s_result]) return graph, inputcells
def emulate_pbc_call(self, unique_key, pbc, args_s, replace=[], callback=None): """For annotating some operation that causes indirectly a Python function to be called. The annotation of the function is "pbc", and the list of annotations of arguments is "args_s". Can be called in various contexts, but from compute_annotation() or compute_result_annotation() of an ExtRegistryEntry, call it with both "unique_key" and "callback" set to "self.bookkeeper.position_key". If there are several calls from the same operation, they need their own "unique_key", like (position_key, "first") and (position_key, "second"). In general, "unique_key" should somehow uniquely identify where the call is in the source code, and "callback" can be either a position_key to reflow from when we see more general results, or a real callback function that will be called with arguments # "(annotator, called_graph)" whenever the result is generalized. "replace" can be set to a list of old unique_key values to forget now, because the given "unique_key" replaces them. """ emulate_enter = not hasattr(self, 'position_key') if emulate_enter: self.enter(None) try: emulated_pbc_calls = self.emulated_pbc_calls prev = [unique_key] prev.extend(replace) for other_key in prev: if other_key in emulated_pbc_calls: del emulated_pbc_calls[other_key] emulated_pbc_calls[unique_key] = pbc, args_s args = simple_args(args_s) if callback is None: emulated = True else: emulated = callback return self.pbc_call(pbc, args, emulated=emulated) finally: if emulate_enter: self.leave()
def get_call_parameters(self, args_s): args = simple_args(args_s) inputcells = self.parse_arguments(args) graph = self.specialize(inputcells) assert isinstance(graph, FunctionGraph) # if that graph has a different signature, we need to re-parse # the arguments. # recreate the args object because inputcells may have been changed new_args = args.unmatch_signature(self.signature, inputcells) inputcells = self.parse_arguments(new_args, graph) signature = getattr(self.pyobj, '_signature_', None) if signature: s_result = finish_type(signature[1], self.bookkeeper, self.pyobj) if s_result is not None: self.bookkeeper.annotator.addpendingblock( graph, graph.returnblock, [s_result]) return graph, inputcells
def get_call_parameters(self, function, args_s, policy): desc = self.bookkeeper.getdesc(function) args = simple_args(args_s) result = [] def schedule(graph, inputcells): result.append((graph, inputcells)) return annmodel.s_ImpossibleValue prevpolicy = self.policy self.policy = policy self.bookkeeper.enter(None) try: desc.pycall(schedule, args, annmodel.s_ImpossibleValue) finally: self.bookkeeper.leave() self.policy = prevpolicy [(graph, inputcells)] = result return graph, inputcells
def _emulate_call(self, meth_name, *args_s): bk = getbookkeeper() s_attr = self._true_getattr(meth_name) # record for calltables bk.emulate_pbc_call(bk.position_key, s_attr, args_s) return s_attr.call(simple_args(args_s))
def simple_call(self, *args_s): return self.call(simple_args(args_s))
def simple_call_SomeObject(annotator, func, *args): return annotator.annotation(func).call( simple_args([annotator.annotation(arg) for arg in args]))
def simple_call_SomeObject(annotator, func, *args): s_func = annotator.annotation(func) argspec = simple_args([annotator.annotation(arg) for arg in args]) return s_func.call(argspec)
def compute_at_fixpoint(self): # getbookkeeper() needs to work during this function, so provide # one with a dummy position self.enter(None) try: def call_sites(): newblocks = self.annotator.added_blocks if newblocks is None: newblocks = self.annotator.annotated # all of them binding = self.annotator.binding for block in newblocks: for op in block.operations: if op.opname in ('simple_call', 'call_args'): yield op # some blocks are partially annotated if binding(op.result, None) is None: break # ignore the unannotated part for call_op in call_sites(): self.consider_call_site(call_op) for pbc, args_s in self.emulated_pbc_calls.itervalues(): args = simple_args(args_s) self.consider_call_site_for_pbc(pbc, args, s_ImpossibleValue, None) self.emulated_pbc_calls = {} finally: self.leave() # sanity check: no flags attached to heap stored instances seen = set() def check_no_flags(s_value_or_def): if isinstance(s_value_or_def, SomeInstance): assert not s_value_or_def.flags, "instance annotation with flags escaped to the heap" check_no_flags(s_value_or_def.classdef) elif isinstance(s_value_or_def, SomeList): check_no_flags(s_value_or_def.listdef.listitem) elif isinstance(s_value_or_def, SomeDict): check_no_flags(s_value_or_def.dictdef.dictkey) check_no_flags(s_value_or_def.dictdef.dictvalue) elif isinstance(s_value_or_def, SomeTuple): for s_item in s_value_or_def.items: check_no_flags(s_item) elif isinstance(s_value_or_def, ClassDef): if s_value_or_def in seen: return seen.add(s_value_or_def) for attr in s_value_or_def.attrs.itervalues(): s_attr = attr.s_value check_no_flags(s_attr) elif isinstance(s_value_or_def, ListItem): if s_value_or_def in seen: return seen.add(s_value_or_def) check_no_flags(s_value_or_def.s_value) for clsdef in self.classdefs: check_no_flags(clsdef)