[pypy-svn] r27068 - pypy/dist/pypy/objspace/std

arigo at codespeak.net arigo at codespeak.net
Thu May 11 13:45:51 CEST 2006


Author: arigo
Date: Thu May 11 13:45:50 2006
New Revision: 27068

Modified:
   pypy/dist/pypy/objspace/std/multimethod.py
   pypy/dist/pypy/objspace/std/stdtypedef.py
Log:
A working version of compressed multimethod.
Still quite slow at start-up.


Modified: pypy/dist/pypy/objspace/std/multimethod.py
==============================================================================
--- pypy/dist/pypy/objspace/std/multimethod.py	(original)
+++ pypy/dist/pypy/objspace/std/multimethod.py	Thu May 11 13:45:50 2006
@@ -39,17 +39,21 @@
             types, order)
         lst[order] = function
 
-    def install(self, prefix, list_of_typeorders, baked_perform_call=True):
+    def install(self, prefix, list_of_typeorders, baked_perform_call=True,
+                base_typeorder=None):
         "NOT_RPYTHON: initialization-time only"
         assert len(list_of_typeorders) == self.arity
         installer = Installer(self, prefix, list_of_typeorders,
-                              baked_perform_call=baked_perform_call)
+                              baked_perform_call=baked_perform_call,
+                              base_typeorder=base_typeorder)
         return installer.install()
 
-    def install_if_not_empty(self, prefix, list_of_typeorders):
+    def install_if_not_empty(self, prefix, list_of_typeorders,
+                             base_typeorder=None):
         "NOT_RPYTHON: initialization-time only"
         assert len(list_of_typeorders) == self.arity
-        installer = Installer(self, prefix, list_of_typeorders)
+        installer = Installer(self, prefix, list_of_typeorders,
+                              base_typeorder=base_typeorder)
         if installer.is_empty():
             return None
         else:
@@ -99,7 +103,8 @@
 
     prefix_memo = {}
 
-    def __init__(self, multimethod, prefix, list_of_typeorders, baked_perform_call=True):
+    def __init__(self, multimethod, prefix, list_of_typeorders,
+                 baked_perform_call=True, base_typeorder=None):
         self.multimethod = multimethod
         # avoid prefix clashes, user code should supply different prefixes
         # itself for nice names in tracebacks
@@ -362,10 +367,9 @@
 
 
 class CompressedArray(object):
-    def __init__(self, null_value, reserved_count):
+    def __init__(self, null_value):
         self.null_value = null_value
-        self.reserved_count = reserved_count
-        self.items = [null_value] * reserved_count
+        self.items = [null_value]
 
     def ensure_length(self, newlen):
         if newlen > len(self.items):
@@ -374,12 +378,9 @@
     def insert_subarray(self, array):
         # insert the given array of numbers into the indexlist,
         # allowing null values to become non-null
-        initial_nulls = 0
-        for item in array:
-            if item != self.null_value:
-                break
-            initial_nulls += 1
-        test = max(self.reserved_count - initial_nulls, 0)
+        if array.count(self.null_value) == len(array):
+            return 0
+        test = 1
         while True:
             self.ensure_length(test+len(array))
             for i in range(len(array)):
@@ -415,14 +416,11 @@
         self.attrname = '__mrd%d_typenum' % self.id
         for t1, num in self.typenum.items():
             setattr(t1, self.attrname, num)
-        self.indexarray = CompressedArray(0, 1)
-        self.allarrays = [self.indexarray]
+        self.indexarray = CompressedArray(0)
 
     def normalize_length(self, next_array):
-        self.allarrays.append(next_array)
-        length = max([len(a.items) for a in self.allarrays])
-        for a in self.allarrays:
-            a.ensure_length(length)
+        # make sure that the indexarray is not smaller than any funcarray
+        self.indexarray.ensure_length(len(next_array.items))
 
 
 class FuncEntry(object):
@@ -446,12 +444,14 @@
         name = min(self.possiblenames)   # pick a random one, but consistently
         self.compress_typechecks(mrdtable)
         checklines = self.generate_typechecks(fnargs[nbargs_before:], mrdtable)
-        source = 'def %s(%s):\n    %s\n    %s\n' % (name, ', '.join(fnargs),
-                                                    '\n    '.join(checklines),
-                                                    self.body)
-        print '_' * 60
-        print self.possiblenames
-        print source
+        if checklines == ['pass']:
+            body = self.body
+        else:
+            checklines.append(self.body)
+            body = '\n    '.join(checklines)
+        source = 'def %s(%s):\n    %s\n' % (name, ', '.join(fnargs), body)
+        #print '_' * 60
+        #print source
         exec compile2(source) in self.miniglobals
         self._function = self.miniglobals[name]
         return self._function
@@ -507,8 +507,6 @@
         typeidexprs = ['%s.%s' % (arg, mrdtable.attrname) for arg in args]
         result = []
         generate(self.typetree)
-        if result == ['pass']:
-            del result[:]
         return result
 
 
@@ -518,8 +516,8 @@
     mrdtables = {}
 
     def __init__(self, multimethod, prefix, list_of_typeorders,
-                 baked_perform_call=True):
-        print 'InstallerVersion2:', prefix
+                 baked_perform_call=True, base_typeorder=None):
+        #print 'InstallerVersion2:', prefix
         self.multimethod = multimethod
         self.prefix = prefix
         self.list_of_typeorders = list_of_typeorders
@@ -530,10 +528,12 @@
                        multimethod.argnames_after)
 
         # compute the complete table
-        assert multimethod.arity == 2
-        assert list_of_typeorders[0] == list_of_typeorders[1]
+        base_typeorder = base_typeorder or list_of_typeorders[0]
+        for typeorder in list_of_typeorders:
+            for t1 in typeorder:
+                assert t1 in base_typeorder
 
-        lst = list(list_of_typeorders[0])
+        lst = list(base_typeorder)
         lst.sort()
         key = tuple(lst)
         try:
@@ -543,61 +543,87 @@
 
         dispatcher = MMDispatcher(multimethod, list_of_typeorders)
         self.table = {}
-        for t0 in list_of_typeorders[0]:
-            for t1 in list_of_typeorders[1]:
-                calllist = dispatcher.expressions([t0, t1],
+        def buildtable(prefixtypes):
+            if len(prefixtypes) == multimethod.arity:
+                calllist = dispatcher.expressions(prefixtypes,
                                                   multimethod.argnames_before,
                                                   args,
                                                   multimethod.argnames_after)
                 if calllist:
-                    self.table[t0, t1] = calllist
+                    self.table[prefixtypes] = calllist
+            else:
+                typeorder = list_of_typeorders[len(prefixtypes)]
+                for t1 in typeorder:
+                    buildtable(prefixtypes + (t1,))
+        buildtable(())
 
     def is_empty(self):
         return len(self.table) == 0
 
     def install(self):
         nskip = len(self.multimethod.argnames_before)
-        null_entry = self.build_funcentry(self.prefix + '0fail', [])
+        null_entry = self.build_funcentry(self.prefix + '_0_fail', [])
         null_entry.no_typecheck()
         if self.is_empty():
             return self.answer(null_entry)
 
-        entryarray = CompressedArray(null_entry, 1)
+        entryarray = CompressedArray(null_entry)
         indexarray = self.mrdtable.indexarray
         lst = self.mrdtable.list_of_types
         indexline = []
-        for num0, t0 in enumerate(lst):
-            flatline = []
-            for num1, t1 in enumerate(lst):
-                calllist = self.table.get((t0, t1), [])
-                funcname = '_'.join([self.prefix, t0.__name__, t1.__name__])
+
+        def compress(typesprefix, typesnum):
+            if len(typesprefix) == self.multimethod.arity:
+                calllist = self.table.get(typesprefix, [])
+                funcname = [self.prefix]
+                for t1 in typesprefix:
+                    funcname.append(t1.__name__)
+                funcname = '_'.join(funcname)
                 entry = self.build_funcentry(funcname, calllist)
-                entry.register_valid_types((num0, num1))
-                flatline.append(entry)
-            index = entryarray.insert_subarray(flatline)
-            indexline.append(index)
+                entry.register_valid_types(typesnum)
+                return entry
+            else:
+                flatline = []
+                for num1, t1 in enumerate(lst):
+                    item = compress(typesprefix + (t1,), typesnum + (num1,))
+                    flatline.append(item)
+                if len(typesprefix) == self.multimethod.arity - 1:
+                    array = entryarray
+                else:
+                    array = indexarray
+                return array.insert_subarray(flatline)
 
-        master_index = indexarray.insert_subarray(indexline)
+        master_index = compress((), ())
 
         null_func = null_entry.make_function(self.fnargs, nskip, self.mrdtable)
-        funcarray = CompressedArray(null_func, 0)
-        for entry in entryarray.items:
+        funcarray = CompressedArray(null_func)
+        # round up the length to a power of 2
+        N = 1
+        while N < len(entryarray.items):
+            N *= 2
+        funcarray.ensure_length(N)
+        for i, entry in enumerate(entryarray.items):
             func = entry.make_function(self.fnargs, nskip, self.mrdtable)
-            funcarray.items.append(func)
+            funcarray.items[i] = func
         self.mrdtable.normalize_length(funcarray)
 
-        print master_index
-        print indexarray.items
-        print funcarray.items
+        #print master_index
+        #print indexarray.items
+        #print funcarray.items
 
         attrname = self.mrdtable.attrname
-        exprfn = "funcarray.items[indexarray.items[%d + arg0.%s] + arg1.%s]" %(
-            master_index, attrname, attrname)
+        exprfn = "%d" % master_index
+        for n in range(self.multimethod.arity-1):
+            exprfn = "indexarray.items[%s + arg%d.%s]" % (exprfn, n, attrname)
+        n = self.multimethod.arity-1
+        exprfn = "funcarray.items[(%s + arg%d.%s) & mmmask]" % (exprfn, n,
+                                                                attrname)
         expr = Call(exprfn, self.fnargs)
-        entry = self.build_funcentry(self.prefix + '0perform_call',
+        entry = self.build_funcentry(self.prefix + '_0_perform_call',
                                      [expr],
                                      indexarray = indexarray,
-                                     funcarray = funcarray)
+                                     funcarray = funcarray,
+                                     mmmask = N-1)
         entry.no_typecheck()
         return self.answer(entry)
 

Modified: pypy/dist/pypy/objspace/std/stdtypedef.py
==============================================================================
--- pypy/dist/pypy/objspace/std/stdtypedef.py	(original)
+++ pypy/dist/pypy/objspace/std/stdtypedef.py	Thu May 11 13:45:50 2006
@@ -279,7 +279,8 @@
             prefix, list_of_typeorders = sliced_typeorders(
                 space.model.typeorder, multimethod, typedef, i, local=local)
             exprargs, expr, miniglobals, fallback = multimethod.install(prefix, list_of_typeorders,
-                                                                        baked_perform_call=False)
+                                                                        baked_perform_call=False,
+                                                                        base_typeorder=space.model.typeorder)
             if fallback:
                 return None   # skip empty multimethods
             trampoline = make_perform_trampoline(prefix, exprargs, expr, miniglobals,



More information about the Pypy-commit mailing list