def complete(self, show_progress=True): assert not self.completed if self.translator and self.translator.rtyper: do_the_getting(self, self.translator.rtyper) def dump(): lst = ['%s: %d' % keyvalue for keyvalue in self.containerstats.items()] lst.sort() log.event('%8d nodes [ %s ]' % (i, ' '.join(lst))) i = self.completedcontainers if show_progress: show_i = (i//1000 + 1) * 1000 else: show_i = -1 # The order of database completion is fragile with gc transformers. # Here is what occurs: # # 1. follow dependencies recursively from the entry point: data # structures pointing to other structures or functions, and # constants in functions pointing to other structures or functions. # Because of the mixlevelannotator, this might find delayed # (not-annotated-and-rtyped-yet) function pointers. They are # not followed at this point. User finalizers (__del__) on the # other hand are followed during this step too. # # 2. gctransformer.finish_helpers() - after this, all functions in # the program have been rtyped. # # 3. follow new dependencies. All previously delayed functions # should have been resolved by 2 - they are gc helpers, like # ll_finalize(). New FuncNodes are built for them. No more # FuncNodes can show up after this step. # # 4. gctransformer.finish_tables() - freeze the gc types table. # # 5. follow new dependencies (this should be only the gc type table, # which contains only numbers and pointers to ll_finalizer # functions seen in step 3). # # This is implemented by interleaving the follow-new-dependencies # steps with calls to the next 'finish' function from the following # list: finish_callbacks = [] if self.gctransformer: finish_callbacks.append(('GC transformer: finished helpers', self.gctransformer.finish_helpers)) finish_callbacks.append(('GC transformer: finished tables', self.gctransformer.get_finish_tables())) def add_dependencies(newdependencies, parent=None): for value in newdependencies: #if isinstance(value, _uninitialized): # continue if isinstance(value, lltype._uninitialized): continue if isinstance(typeOf(value), ContainerType): node = self.getcontainernode(value) if parent and node._funccodegen_owner is not None: node._funccodegen_owner = parent._funccodegen_owner else: self.get(value, parent and parent._funccodegen_owner) while True: while True: while self.pendingsetupnodes: lst = self.pendingsetupnodes self.pendingsetupnodes = [] for nodedef in lst: nodedef.setup() if i == len(self.containerlist): break node = self.containerlist[i] add_dependencies(node.enum_dependencies(), node) i += 1 self.completedcontainers = i if i == show_i: dump() show_i += 1000 if self.delayedfunctionptrs: lst = self.delayedfunctionptrs self.delayedfunctionptrs = [] progress = False for fnptr in lst: try: fnptr._obj except lltype.DelayedPointer: # still not resolved self.delayedfunctionptrs.append(fnptr) else: self.get(fnptr) progress = True if progress: continue # progress - follow all dependencies again if finish_callbacks: logmsg, finish = finish_callbacks.pop(0) if not hasattr(finish, 'next'): newdependencies = finish() else: # if 'finish' is a generator, consume the next element # and put the generator again in the queue try: newdependencies = finish.next() finish_callbacks.insert(0, (None, finish)) except StopIteration: newdependencies = None if logmsg: log.database(logmsg) if newdependencies: add_dependencies(newdependencies) continue # progress - follow all dependencies again break # database is now complete assert not self.delayedfunctionptrs self.completed = True if show_progress: dump() log.database("Completed")
def complete(self, show_progress=True): assert not self.completed if self.translator and self.translator.rtyper: do_the_getting(self, self.translator.rtyper) def dump(): lst = [ '%s: %d' % keyvalue for keyvalue in self.containerstats.items() ] lst.sort() log.event('%8d nodes [ %s ]' % (i, ' '.join(lst))) i = self.completedcontainers if show_progress: show_i = (i // 1000 + 1) * 1000 else: show_i = -1 # The order of database completion is fragile with gc transformers. # Here is what occurs: # # 1. follow dependencies recursively from the entry point: data # structures pointing to other structures or functions, and # constants in functions pointing to other structures or functions. # Because of the mixlevelannotator, this might find delayed # (not-annotated-and-rtyped-yet) function pointers. They are # not followed at this point. User finalizers (__del__) on the # other hand are followed during this step too. # # 2. gctransformer.finish_helpers() - after this, all functions in # the program have been rtyped. # # 3. follow new dependencies. All previously delayed functions # should have been resolved by 2 - they are gc helpers, like # ll_finalize(). New FuncNodes are built for them. No more # FuncNodes can show up after this step. # # 4. gctransformer.finish_tables() - freeze the gc types table. # # 5. follow new dependencies (this should be only the gc type table, # which contains only numbers and pointers to ll_finalizer # functions seen in step 3). # # This is implemented by interleaving the follow-new-dependencies # steps with calls to the next 'finish' function from the following # list: finish_callbacks = [] if self.gctransformer: finish_callbacks.append(('GC transformer: finished helpers', self.gctransformer.get_finish_helpers())) finish_callbacks.append(('GC transformer: finished tables', self.gctransformer.get_finish_tables())) def add_dependencies(newdependencies, parent=None): for value in newdependencies: #if isinstance(value, _uninitialized): # continue if isinstance(value, lltype._uninitialized): continue if isinstance(typeOf(value), ContainerType): node = self.getcontainernode(value) if parent and node._funccodegen_owner is not None: node._funccodegen_owner = parent._funccodegen_owner else: self.get(value, parent and parent._funccodegen_owner) while True: while True: while self.pendingsetupnodes: lst = self.pendingsetupnodes self.pendingsetupnodes = [] for nodedef in lst: nodedef.setup() if i == len(self.containerlist): break node = self.containerlist[i] add_dependencies(node.enum_dependencies(), node) i += 1 self.completedcontainers = i if i == show_i: dump() show_i += 1000 if self.delayedfunctionptrs: lst = self.delayedfunctionptrs self.delayedfunctionptrs = [] progress = False for fnptr in lst: try: fnptr._obj except lltype.DelayedPointer: # still not resolved self.delayedfunctionptrs.append(fnptr) else: self.get(fnptr) progress = True if progress: continue # progress - follow all dependencies again if finish_callbacks: logmsg, finish = finish_callbacks.pop(0) if not hasattr(finish, 'next'): newdependencies = finish() else: # if 'finish' is a generator, consume the next element # and put the generator again in the queue try: newdependencies = finish.next() finish_callbacks.insert(0, (None, finish)) except StopIteration: newdependencies = None if logmsg: log.database(logmsg) if newdependencies: add_dependencies(newdependencies) continue # progress - follow all dependencies again break # database is now complete assert not self.delayedfunctionptrs self.completed = True if self.gctransformer is not None: log.database("Inlining GC helpers and postprocessing") self.gctransformer.inline_helpers_and_postprocess( self.all_graphs()) if show_progress: dump() log.database("Completed")