[pypy-svn] r16172 - in pypy/dist/pypy: annotation rpython rpython/module

arigo at codespeak.net arigo at codespeak.net
Fri Aug 19 19:09:04 CEST 2005


Author: arigo
Date: Fri Aug 19 19:08:54 2005
New Revision: 16172

Added:
   pypy/dist/pypy/rpython/rexternalobj.py   (contents, props changed)
Modified:
   pypy/dist/pypy/annotation/bookkeeper.py
   pypy/dist/pypy/annotation/builtin.py
   pypy/dist/pypy/annotation/model.py
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/rpython/annlowlevel.py
   pypy/dist/pypy/rpython/extfunctable.py
   pypy/dist/pypy/rpython/module/support.py
   pypy/dist/pypy/rpython/rbuiltin.py
   pypy/dist/pypy/rpython/rmodel.py
   pypy/dist/pypy/rpython/rspecialcase.py
   pypy/dist/pypy/rpython/rtyper.py
Log:
Support for "external types" for annotation and rtyping, following the same
lines as external functions.  Some types like thread.LockType can be declared
in the new "typetable" of rpython.extfunctable.  These types must have a
simple interface -- basically, only methods, which are themselves external
functions.

The annotator uses a new SomeExternalObject to track objects of one of these
external types.  The rtyper turns them into pointers to opaque data.  There is
some changes all over the place to support this kind of usage of opaque data;
I'm not sure yet if it's really nice to use opaque types for this, because I'm
unsure how to support the result in genc.  (The problem is that this gives
pointers to opaque objects that still need the same memory management as
pointers to regular structs...)



Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py	(original)
+++ pypy/dist/pypy/annotation/bookkeeper.py	Fri Aug 19 19:08:54 2005
@@ -5,7 +5,7 @@
 from __future__ import generators
 import sys
 from types import FunctionType, ClassType, MethodType
-from types import BuiltinMethodType
+from types import BuiltinMethodType, NoneType
 from pypy.tool.ansi_print import ansi_print
 from pypy.annotation.model import *
 from pypy.annotation.classdef import ClassDef, isclassdef
@@ -168,9 +168,7 @@
 
     def __setstate__(self, dic):
         self.__dict__.update(dic) # normal action
-        # import ordering hack
-        global BUILTIN_ANALYZERS
-        from pypy.annotation.builtin import BUILTIN_ANALYZERS
+        delayed_imports()
 
     def __init__(self, annotator):
         self.annotator = annotator
@@ -201,9 +199,7 @@
 
         self.stats = Stats(self)
 
-        # import ordering hack
-        global BUILTIN_ANALYZERS
-        from pypy.annotation.builtin import BUILTIN_ANALYZERS
+        delayed_imports()
 
     def count(self, category, *args):
         self.stats.count(category, *args)
@@ -337,6 +333,8 @@
                     result.dictdef.generalize_value(self.immutablevalue(ev))
         elif ishashable(x) and x in BUILTIN_ANALYZERS:
             result = SomeBuiltin(BUILTIN_ANALYZERS[x], methodname="%s.%s" % (x.__module__, x.__name__))
+        elif tp in EXTERNAL_TYPE_ANALYZERS:
+            result = SomeExternalObject(tp)
         elif isinstance(x, lltype._ptr):
             result = SomePtr(lltype.typeOf(x))
         elif isinstance(x, lladdress.address):
@@ -349,9 +347,8 @@
                 x.im_self._freeze_()
             if hasattr(x, '__self__') and x.__self__ is not None:
                 s_self = self.immutablevalue(x.__self__)
-                try:
-                    result = s_self.find_method(x.__name__)
-                except AttributeError:
+                result = s_self.find_method(x.__name__)
+                if result is None:
                     result = SomeObject()
             else:
                 return self.getpbc(x)
@@ -418,6 +415,10 @@
         elif t is dict:
             return SomeDict(MOST_GENERAL_DICTDEF)
         # can't do tuple
+        elif t is NoneType:
+            return self.getpbc(None)
+        elif t in EXTERNAL_TYPE_ANALYZERS:
+            return SomeExternalObject(t)
         elif t.__module__ != '__builtin__' and t not in self.pbctypes:
             classdef = self.getclassdef(t)
             return SomeInstance(classdef)
@@ -712,3 +713,10 @@
         return TLS.bookkeeper
     except AttributeError:
         return None
+
+
+def delayed_imports():
+    # import ordering hack
+    global BUILTIN_ANALYZERS, EXTERNAL_TYPE_ANALYZERS
+    from pypy.annotation.builtin import BUILTIN_ANALYZERS
+    from pypy.annotation.builtin import EXTERNAL_TYPE_ANALYZERS

Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py	(original)
+++ pypy/dist/pypy/annotation/builtin.py	Fri Aug 19 19:08:54 2005
@@ -262,6 +262,7 @@
 # collect all functions
 import __builtin__
 BUILTIN_ANALYZERS = {}
+EXTERNAL_TYPE_ANALYZERS = {}
 for name, value in globals().items():
     if name.startswith('builtin_'):
         original = getattr(__builtin__, name[8:])
@@ -366,8 +367,19 @@
 
 from pypy.rpython import extfunctable
 
-# import annotation information for external functions 
-# from the extfunctable.table  into our own annotation specific table 
-for func, extfuncinfo in extfunctable.table.iteritems():
-    BUILTIN_ANALYZERS[func] = extfuncinfo.annotation 
+def update_exttables():
 
+    # import annotation information for external functions 
+    # from the extfunctable.table  into our own annotation specific table 
+    for func, extfuncinfo in extfunctable.table.iteritems():
+        BUILTIN_ANALYZERS[func] = extfuncinfo.annotation 
+
+    # import annotation information for external types
+    # from the extfunctable.typetable  into our own annotation specific table 
+    for typ, exttypeinfo in extfunctable.typetable.iteritems():
+        EXTERNAL_TYPE_ANALYZERS[typ] = exttypeinfo.get_annotations()
+
+# Note: calls to declare() may occur after builtin.py is first imported.
+# We must track future changes to the extfunctables.
+extfunctable.table_callbacks.append(update_exttables)
+update_exttables()

Modified: pypy/dist/pypy/annotation/model.py
==============================================================================
--- pypy/dist/pypy/annotation/model.py	(original)
+++ pypy/dist/pypy/annotation/model.py	Fri Aug 19 19:08:54 2005
@@ -380,6 +380,19 @@
     def can_be_none(self):
         return False
 
+
+class SomeExternalObject(SomeObject):
+    """Stands for an object of 'external' type.  External types are defined
+    in pypy.rpython.extfunctable.declaretype(), and represent simple types
+    with some methods that need direct back-end support."""
+
+    def __init__(self, knowntype):
+        self.knowntype = knowntype
+
+    def can_be_none(self):
+        return True
+
+
 class SomeImpossibleValue(SomeObject):
     """The empty set.  Instances are placeholders for objects that
     will never show up at run-time, e.g. elements of an empty list."""

Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Fri Aug 19 19:08:54 2005
@@ -11,6 +11,7 @@
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
 from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeFloat
 from pypy.annotation.model import SomeIterator, SomePBC, new_or_old_class
+from pypy.annotation.model import SomeExternalObject
 from pypy.annotation.model import SomeTypedAddressAccess, SomeAddress
 from pypy.annotation.model import unionof, set, setunion, missing_operation
 from pypy.annotation.bookkeeper import getbookkeeper, RPythonCallsSpace
@@ -119,18 +120,21 @@
 
     def find_method(obj, name):
         "Look for a special-case implementation for the named method."
-        analyser = getattr(obj.__class__, 'method_' + name)
-        return SomeBuiltin(analyser, obj, name)
+        try:
+            analyser = getattr(obj.__class__, 'method_' + name)
+        except AttributeError:
+            return None
+        else:
+            return SomeBuiltin(analyser, obj, name)
 
     def getattr(obj, s_attr):
         # get a SomeBuiltin if the SomeObject has
         # a corresponding method to handle it
         if s_attr.is_constant() and isinstance(s_attr.const, str):
             attr = s_attr.const
-            try:
-                return obj.find_method(attr)
-            except AttributeError:
-                pass
+            s_method = obj.find_method(attr)
+            if s_method is not None:
+                return s_method
             # if the SomeObject is itself a constant, allow reading its attrs
             if obj.is_constant() and hasattr(obj.const, attr):
                 return immutablevalue(getattr(obj.const, attr))
@@ -306,7 +310,10 @@
     def method_endswith(str, frag):
         return SomeBool()
 
-    def method_find(str, frag):
+    def method_find(str, frag, start=None, end=None):
+        return SomeInteger()
+
+    def method_rfind(str, frag, start=None, end=None):
         return SomeInteger()
 
     def method_join(str, s_list):
@@ -480,6 +487,16 @@
         return immutablevalue(outcome)
 
 
+class __extend__(SomeExternalObject):
+    def find_method(obj, name):
+        "Look for a special-case implementation for the named method."
+        type_analyser = builtin.EXTERNAL_TYPE_ANALYZERS[obj.knowntype]
+        if name in type_analyser:
+            analyser = type_analyser[name]
+            return SomeBuiltin(analyser, obj, name)
+        return SomeObject.find_method(obj, name)
+
+
 # annotation of low-level types
 from pypy.annotation.model import SomePtr, ll_to_annotation, annotation_to_lltype
 class __extend__(SomePtr):

Modified: pypy/dist/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/dist/pypy/rpython/annlowlevel.py	(original)
+++ pypy/dist/pypy/rpython/annlowlevel.py	Fri Aug 19 19:08:54 2005
@@ -5,7 +5,9 @@
 import types
 from pypy.annotation import model as annmodel
 from pypy.annotation.specialize import decide_callable
-from pypy.annotation.policy import BasicAnnotatorPolicy
+from pypy.annotation.policy import AnnotatorPolicy
+from pypy.rpython import lltype
+from pypy.rpython import extfunctable
 
 def not_const(s_obj): # xxx move it somewhere else
     if s_obj.is_constant():
@@ -29,10 +31,10 @@
     def __str__(self):
         return getattr(self.val, '__name__', repr(self.val)) + 'Const'
 
-class LowLevelAnnotatorPolicy(BasicAnnotatorPolicy):
+class LowLevelAnnotatorPolicy(AnnotatorPolicy):
     allow_someobjects = False
 
-    def specialize(pol, bookkeeper, spaceop, func, args, mono):
+    def default_specialize(pol, bookkeeper, ignored, spaceop, func, args, mono):
         args_s, kwds_s = args.unpack()
         assert not kwds_s
         if not args_s or not isinstance(func, types.FunctionType):
@@ -53,7 +55,20 @@
                     # for module/ll_*
                     key.append(s_obj.__class__)
         return tuple(key), bookkeeper.build_args('simple_call', new_args_s)
-        
+
+    def override__to_rexternalobj(pol, s_obj):
+        assert isinstance(s_obj, annmodel.SomeExternalObject)
+        exttypeinfo = extfunctable.typetable[s_obj.knowntype]
+        OPAQUE = exttypeinfo.get_opaque_lltype()
+        return annmodel.SomePtr(lltype.Ptr(OPAQUE))
+
+    def override__from_rexternalobj(pol, s_objptr):
+        assert isinstance(s_objptr, annmodel.SomePtr)
+        OPAQUE = s_objptr.ll_ptrtype.TO
+        assert isinstance(OPAQUE, lltype.OpaqueType)
+        exttypeinfo = OPAQUE.exttypeinfo
+        return annmodel.SomeExternalObject(exttypeinfo.typ)
+
 
 def annotate_lowlevel_helper(annotator, ll_function, args_s):
     saved = annotator.policy

Modified: pypy/dist/pypy/rpython/extfunctable.py
==============================================================================
--- pypy/dist/pypy/rpython/extfunctable.py	(original)
+++ pypy/dist/pypy/rpython/extfunctable.py	Fri Aug 19 19:08:54 2005
@@ -11,9 +11,12 @@
     def __init__(self, func, annotation, ll_function_path, ll_annotable, backend_functiontemplate):
         self.func = func
         self.annotation = annotation
-        modulename, ignored = ll_function_path.split('/')
-        self.ll_module = ImportMe('pypy.rpython.module.%s' % modulename)
-        self.ll_function_name = ll_function_path.replace('/', '_')
+        modulename, tail = ll_function_path.split('/')
+        if '.' not in modulename:
+            modulename = 'pypy.rpython.module.%s' % modulename
+        self.ll_module = ImportMe(modulename)
+        lastmodulename = modulename[modulename.rfind('.')+1:]
+        self.ll_function_name = '%s_%s' % (lastmodulename, tail)
         self.ll_annotable = ll_annotable
         self.backend_functiontemplate = backend_functiontemplate
 
@@ -24,6 +27,34 @@
     ll_function = property(get_ll_function)
 
 
+class ExtTypeInfo:
+    def __init__(self, typ, tag, methods):
+        self.typ = typ
+        self.tag = tag
+        self.TYPE = None
+        self.methods = methods     # {'name': ExtFuncInfo()}
+
+    def get_annotation(self, methodname):
+        return self.methods[methodname].annotation
+
+    def get_annotations(self):
+        return dict([(name, self.get_annotation(name))
+                     for name in self.methods])
+
+    def get_func_infos(self):
+        for extfuncinfo in self.methods.itervalues():
+            if extfuncinfo.func is not None:
+                yield (extfuncinfo.func, extfuncinfo)
+
+    def get_opaque_lltype(self):
+        if self.TYPE is None:
+            from pypy.rpython import lltype
+            OPAQUE = lltype.OpaqueType(self.tag)
+            OPAQUE.exttypeinfo = self
+            self.TYPE = OPAQUE
+        return self.TYPE
+
+
 class ImportMe:
     "Lazily imported module, for circular imports :-/"
     def __init__(self, modulename):
@@ -35,6 +66,8 @@
         return self._mod
 
 
+table_callbacks = []   # to track declare() that occur after 'table' is read
+
 table = {}
 def declare(func, annotation, ll_function, ll_annotable=True, backend_functiontemplate=None):
     # annotation can be a function computing the annotation
@@ -45,7 +78,31 @@
         def annotation(*args_s):
             from pypy.annotation import bookkeeper
             return bookkeeper.getbookkeeper().valueoftype(typ)
-    table[func] = ExtFuncInfo(func, annotation, ll_function, ll_annotable, backend_functiontemplate)
+    info = ExtFuncInfo(func, annotation, ll_function, ll_annotable, backend_functiontemplate)
+    if func is not None:
+        table[func] = info
+        for callback in table_callbacks:
+            callback()
+    return info
+
+typetable = {}
+def declaretype(typ, tag, **methodsdecl):
+    assert isinstance(typ, type)
+    methods = {}
+    for name, args in methodsdecl.items():
+        # try to get the method object from the typ
+        for cls in typ.__mro__:
+            if name in typ.__dict__:
+                func = typ.__dict__[name]
+                break
+        else:
+            func = None   # failed (typical for old-style C types), ignore it
+        methods[name] = declare(func, *args)
+    info = ExtTypeInfo(typ, tag, methods)
+    typetable[typ] = info
+    for callback in table_callbacks:
+        callback()
+    return info
 
 # _____________________________________________________________
 

Modified: pypy/dist/pypy/rpython/module/support.py
==============================================================================
--- pypy/dist/pypy/rpython/module/support.py	(original)
+++ pypy/dist/pypy/rpython/module/support.py	Fri Aug 19 19:08:54 2005
@@ -1,3 +1,5 @@
+from pypy.rpython import lltype
+from pypy.rpython import extfunctable
 from pypy.rpython.rstr import STR
 from pypy.rpython.lltype import GcStruct, Signed, Array, Char, Ptr, malloc
 
@@ -17,3 +19,13 @@
     while i < n:
         dstchars[i] = srcchars[i]
         i += 1
+
+def to_rexternalobj(obj):
+    exttypeinfo = extfunctable.typetable[type(obj)]
+    OPAQUE = exttypeinfo.get_opaque_lltype()
+    return lltype.opaqueptr(OPAQUE, name=None, externalobj=obj)
+to_rexternalobj._annspecialcase_ = "override:to_rexternalobj"
+
+def from_rexternalobj(objptr):
+    return objptr._obj.externalobj
+from_rexternalobj._annspecialcase_ = "override:from_rexternalobj"

Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/rbuiltin.py	Fri Aug 19 19:08:54 2005
@@ -288,8 +288,10 @@
             return hop.llops.genexternalcall(ll_function.__name__, vars, resulttype=resulttype,
                                              _callable = ll_function)
             
-    return sourcetools.func_with_new_name(rtype_extfunc,
-                                          "rtype_extfunc_%s" % extfuncinfo.func.__name__)
+    if extfuncinfo.func is not None:
+        rtype_extfunc = sourcetools.func_with_new_name(rtype_extfunc,
+            "rtype_extfunc_%s" % extfuncinfo.func.__name__)
+    return rtype_extfunc
 
 # import rtyping information for external functions 
 # from the extfunctable.table  into our own specific table 

Added: pypy/dist/pypy/rpython/rexternalobj.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rexternalobj.py	Fri Aug 19 19:08:54 2005
@@ -0,0 +1,29 @@
+from pypy.annotation.pairtype import pairtype
+from pypy.annotation import model as annmodel
+from pypy.rpython import lltype
+from pypy.rpython.rmodel import Repr
+from pypy.rpython.extfunctable import typetable
+from pypy.rpython import rbuiltin
+from pypy.tool import sourcetools
+
+
+class __extend__(annmodel.SomeExternalObject):
+    def rtyper_makerepr(self, rtyper):
+        return ExternalObjRepr(self.knowntype)
+    def rtyper_makekey(self):
+        return self.__class__, self.knowntype
+
+
+class ExternalObjRepr(Repr):
+
+    def __init__(self, knowntype):
+        self.exttypeinfo = typetable[knowntype]
+        OPAQUE = self.exttypeinfo.get_opaque_lltype()
+        self.lowleveltype = lltype.Ptr(OPAQUE)
+        # The set of methods supported depends on 'knowntype', so we
+        # cannot have rtype_method_xxx() methods directly on the
+        # ExternalObjRepr class.  But we can store them in 'self' now.
+        for name, extfuncinfo in self.exttypeinfo.methods.items():
+            methodname = 'rtype_method_' + name
+            bltintyper = rbuiltin.make_rtype_extfunc(extfuncinfo)
+            setattr(self, methodname, bltintyper)

Modified: pypy/dist/pypy/rpython/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rmodel.py	(original)
+++ pypy/dist/pypy/rpython/rmodel.py	Fri Aug 19 19:08:54 2005
@@ -114,9 +114,7 @@
         if s_attr.is_constant() and isinstance(s_attr.const, str):
             attr = s_attr.const
             s_obj = hop.args_s[0]
-            try:
-                s_obj.find_method(attr)   # just to check it is here
-            except AttributeError:
+            if s_obj.find_method(attr) is None:
                 raise TyperError("no method %s on %r" % (attr, s_obj))
             else:
                 # implement methods (of a known name) as just their 'self'

Modified: pypy/dist/pypy/rpython/rspecialcase.py
==============================================================================
--- pypy/dist/pypy/rpython/rspecialcase.py	(original)
+++ pypy/dist/pypy/rpython/rspecialcase.py	Fri Aug 19 19:08:54 2005
@@ -27,3 +27,11 @@
 def rtype_override_ignore(hop, clsdef): # ignore works for methods too
     hop.exception_cannot_occur()
     return inputconst(hop.r_result, None)
+
+def rtype_identity_function(hop, clsdef):
+    hop.exception_cannot_occur()
+    v, = hop.inputargs(hop.args_r[0])
+    return v
+
+rtype_override_to_rexternalobj   = rtype_identity_function
+rtype_override_from_rexternalobj = rtype_identity_function

Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py	(original)
+++ pypy/dist/pypy/rpython/rtyper.py	Fri Aug 19 19:08:54 2005
@@ -741,5 +741,6 @@
 from pypy.rpython import rslice
 from pypy.rpython import rlist, rstr, rtuple, rdict 
 from pypy.rpython import rclass, rbuiltin, rpbc, rspecialcase
+from pypy.rpython import rexternalobj
 from pypy.rpython import rptr
 from pypy.rpython import raddress # memory addresses



More information about the Pypy-commit mailing list