[pypy-svn] r6375 - pypy/trunk/src/pypy/translator

arigo at codespeak.net arigo at codespeak.net
Fri Sep 10 12:40:46 CEST 2004


Author: arigo
Date: Fri Sep 10 12:40:46 2004
New Revision: 6375

Modified:
   pypy/trunk/src/pypy/translator/genc_typeset.py
   pypy/trunk/src/pypy/translator/typer.py
Log:
Still cleaning a bit operations and conversions.  See the new logic in
typer.LLFunction.find_best_match().  While generally useful, the precise goal
of this algorithm (next check-in!) is that a user-defined class gets a chance
to generate a custom OP_SET_ATTR for its attributes in the method
CTypeSet.extend_OP_SET_ATTR(), to perform a direct store into the structure,
before the fall-back macro OP_SET_ATTR_ooov() is considered -- which would
generate a conversion of the attribute to PyObject* and a call to
PyObject_SetAttr().



Modified: pypy/trunk/src/pypy/translator/genc_typeset.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genc_typeset.py	(original)
+++ pypy/trunk/src/pypy/translator/genc_typeset.py	Fri Sep 10 12:40:46 2004
@@ -82,31 +82,29 @@
                 self.conversion_errors[sig] = True
                 raise
 
-    def typingerror(self, opname, hltypes):
+    def typemismatch(self, opname, hltypes):
         # build operations on demand, e.g. if they take a variable number
         # of arguments or depend on a constant value (e.g. the class being
         # instantiated).
         try:
-            builder = getattr(self, 'build_' + opname)
+            extender = getattr(self, 'extend_' + opname)
         except AttributeError:
-            return False
-
-        progress = False
-        for newsig, newop in builder(hltypes):
+            return
+        for newsig, newop in extender(hltypes):
+            # record the new operation only if it has a lower cost than
+            # an existing operation with the same signature
             llops = self.lloperations.setdefault(opname, {})
-            if newsig not in llops:
+            if newsig not in llops or newop.cost < llops[newsig].cost:
                 llops[newsig] = newop
-                progress = True
-        return progress
 
     # ____________________________________________________________
 
-    def build_OP_NEWLIST(self, hltypes):
+    def extend_OP_NEWLIST(self, hltypes):
         # LoNewList can build a list of any length from PyObject* args.
         sig = (R_OBJECT,) * len(hltypes)
         yield sig, genc_op.LoNewList
 
-    def build_OP_NEWTUPLE(self, hltypes):
+    def extend_OP_NEWTUPLE(self, hltypes):
         # We can use LoCopy to virtually build a tuple because
         # the tuple representation 'rt' is just the collection of all the
         # representations for the input args.
@@ -114,7 +112,7 @@
         sig = tuple(hltypes[:-1]) + (rt,)
         yield sig, genc_op.LoCopy
 
-    def build_OP_SIMPLE_CALL(self, hltypes):
+    def extend_OP_SIMPLE_CALL(self, hltypes):
         if not hltypes:
             return
         # We can call the function using PyObject_CallFunction(), if
@@ -156,7 +154,7 @@
                     sig = (r,) + sig
                     yield sig, llopcls
 
-    def build_OP_ALLOC_INSTANCE(self, hltypes):
+    def extend_OP_ALLOC_INSTANCE(self, hltypes):
         # OP_ALLOC_INSTANCE is used by the constructor functions xxx_new()
         if not hltypes:
             return

Modified: pypy/trunk/src/pypy/translator/typer.py
==============================================================================
--- pypy/trunk/src/pypy/translator/typer.py	(original)
+++ pypy/trunk/src/pypy/translator/typer.py	Fri Sep 10 12:40:46 2004
@@ -77,10 +77,11 @@
 #       function should return the conversion operation (as a subclass of
 #       LLOp).  Otherwise, it should raise CannotConvert.
 #
-#   def typingerror(self, opname, hltypes):
-#       Called when no match is found in lloperations.  This function must
-#       either extend lloperations and return True to retry, or return
-#       False to fail.
+#   def typemismatch(self, opname, hltypes):
+#       Called when no exact match is found in lloperations.  This function
+#       can extend lloperations[opname] to provide a better match for hltypes.
+#       Partial matches (i.e. ones requiring conversions) are only considered
+#       after this function returns.
 # ____________________________________________________________
 
 
@@ -93,7 +94,7 @@
         self.lloperations = typeset.lloperations
         self.rawoperations= typeset.rawoperations
         self.getconversion= typeset.getconversion
-        self.typingerror  = typeset.typingerror
+        self.typemismatch = typeset.typemismatch
         self.hltypes = {}
         self.llreprs = {}
 
@@ -215,6 +216,42 @@
         # make a new node for the release tree
         self.to_release = ReleaseNode(v, llop, self.to_release)
 
+    def find_best_match(self, opname, args_t, directions):
+        # look for an exact match first
+        llsigs = self.lloperations.setdefault(opname, {})
+        sig = tuple(args_t)
+        if sig in llsigs:
+            return sig, llsigs[sig]
+        # no exact match, give the typeset a chance to provide an
+        # accurate version
+        self.typemismatch(opname, tuple(args_t))
+        if sig in llsigs:
+            return sig, llsigs[sig]
+        # enumerate the existing operation signatures and their costs
+        choices = []
+        for sig, llopcls in llsigs.items():
+            if len(sig) != len(args_t):
+                continue   # wrong number of arguments
+            try:
+                cost = llopcls.cost
+                for hltype1, hltype2, reverse in zip(args_t, sig,
+                                                     directions):
+                    if hltype1 != hltype2:
+                        if reverse:
+                            hltype1, hltype2 = hltype2, hltype1
+                        convop = self.getconversion(hltype1, hltype2)
+                        cost += convop.cost
+                choices.append((cost, sig, llopcls))
+            except CannotConvert:
+                continue   # non-matching signature
+        if choices:
+            cost, sig, llopcls = min(choices)
+            # for performance, cache the approximate match
+            # back into self.lloperations
+            llsigs[sig] = llopcls
+            return sig, llopcls
+        raise TypingError([opname] + list(args_t))
+
     def operation(self, opname, args, result=None, errlabel=None):
         "Helper to build the LLOps for a single high-level operation."
         # get the hltypes of the input arguments
@@ -227,43 +264,9 @@
             self.makevar(result)
             args_t.append(self.hltypes[result])
             directions.append(True)
-        # look for an exact match first
-        llsigs = self.lloperations.get(opname, {})
-        sig = tuple(args_t)
-        if sig in llsigs:
-            llopcls = llsigs[sig]
-        else:
-            # enumerate the existing operation signatures and their costs
-            choices = []
-            for sig, llopcls in llsigs.items():
-                if len(sig) != len(args_t):
-                    continue   # wrong number of arguments
-                try:
-                    cost = llopcls.cost
-                    for hltype1, hltype2, reverse in zip(args_t, sig,
-                                                         directions):
-                        if hltype1 != hltype2:
-                            if reverse:
-                                hltype1, hltype2 = hltype2, hltype1
-                            convop = self.getconversion(hltype1, hltype2)
-                            cost += convop.cost
-                    choices.append((cost, sig, llopcls))
-                except CannotConvert:
-                    continue   # non-matching signature
-            if not choices:
-                retry = self.typingerror(opname, tuple(args_t))
-                # if 'typingerror' did not raise an exception, try again.
-                # infinite recursion here means that 'typingerror' did not
-                # correctly extend 'lloperations'.
-                if retry:
-                    try:
-                        self.operation(opname, args, result, errlabel)
-                        return
-                    except RuntimeError:   # infinite recursion
-                        pass
-                raise TypingError([opname] + args_t)
-            cost, sig, llopcls = min(choices)
-        # convert input args to temporary variables
+        # look for the low-level operation class that implements these types
+        sig, llopcls = self.find_best_match(opname, args_t, directions)
+        # convert input args to temporary variables, if needed
         llargs = []
         for v, v_t, s_t in zip(args, args_t, sig):
             if v_t != s_t:



More information about the Pypy-commit mailing list