File: ann_override.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (158 lines) | stat: -rw-r--r-- 7,266 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# overrides for annotation specific to PyPy codebase
from rpython.annotator.policy import AnnotatorPolicy
from rpython.flowspace.model import Constant
from rpython.annotator.classdesc import InstanceSource

def set_attribute(classdesc, value, attr="_static_lookup_cache"):
    cls = classdesc.pyobj
    if attr in cls.__dict__:
        return
    classdesc.classdict[attr] = Constant(value)
    classdesc.immutable_fields.add(attr)
    classdesc.classdef.add_source_for_attribute(attr, classdesc)
    setattr(cls, attr, value)

class PyPyAnnotatorPolicy(AnnotatorPolicy):
    def __init__(self, space):
        self.lookups = set()
        self.lookups_where = set()
        self.pypytypes = {} # W_Root subclass -> W_TypeObject()
        self.types_w = set()
        self.space = space

    def consider_lookup(self, bookkeeper, attr):
        from pypy.objspace.std import typeobject
        from pypy.interpreter import baseobjspace
        assert attr not in self.lookups
        cached = "cached_%s" % attr
        clsdef = bookkeeper.getuniqueclassdef(StaticLookupCache)
        classdesc = clsdef.classdesc
        set_attribute(classdesc, None, cached)
        for cls, w_type in self.pypytypes.items():
            if cls._static_lookup_cache is not None:
                setattr(cls._static_lookup_cache, cached, w_type._lookup(attr))
                source = InstanceSource(bookkeeper, cls._static_lookup_cache)
                clsdef.add_source_for_attribute(cached, source)
        self.lookups.add(attr)

    def consider_lookup_in_type_where(self, bookkeeper, attr):
        assert attr not in self.lookups_where
        from pypy.objspace.std import typeobject
        cached = "cached_where_%s" % attr
        clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject)
        classdesc = clsdef.classdesc
        classdesc.immutable_fields.add(cached)
        classdesc.classdict[cached] = Constant((None, None))
        clsdef.add_source_for_attribute(cached, classdesc)
        space = self.space
        w_moduletype = space.type(space.sys)
        for w_t in self.types_w:
            if not (w_t.is_heaptype() or w_t.is_cpytype() or
                        space.issubtype_w(w_t, w_moduletype)):
                setattr(w_t, cached, w_t._lookup_where(attr))
                source = InstanceSource(bookkeeper, w_t)
                clsdef.add_source_for_attribute(cached, source)
        self.lookups_where.add(attr)

    def specialize__lookup(self, funcdesc, args_s):
        # approach: add to every subclass of W_Root that does not represent a
        # user-defined class an attribute "_static_lookup_cache" which is an
        # instance of StaticLookupCache. for user-defined subclasses of
        # concrete subclasses of W_Root, _static_lookup_cache is None.
        # then add attributes cached_<special_method_name> to the instances of
        # StaticLookupCache, storing the result of looking up a special method
        # from the type
        s_space, s_obj, s_name = args_s
        if s_name.is_constant():
            attr = s_name.const
            def builder(translator, func):
                #print "LOOKUP", attr
                self.consider_lookup(funcdesc.bookkeeper, attr)
                d = {'__name__': '<ann_override_lookup>'}
                exec CACHED_LOOKUP % {'attr': attr} in d
                return translator.buildflowgraph(d['lookup_'+attr])
            return funcdesc.cachedgraph(attr, builder=builder)
        else:
            return funcdesc.cachedgraph(None) # don't specialize

    def specialize__lookup_in_type_where(self, funcdesc, args_s):
        # lookup_in_type_where works differently, we have a w_type, cache the
        # results on that for non-heaptypes
        s_space, s_type, s_name = args_s
        if s_name.is_constant():
            attr = s_name.const
            def builder(translator, func):
                #print "LOOKUP_IN_TYPE_WHERE", attr
                self.consider_lookup_in_type_where(funcdesc.bookkeeper, attr)
                d = {'__name__': '<ann_override_lookup>'}
                exec CACHED_LOOKUP_IN_TYPE_WHERE % {'attr': attr} in d
                return translator.buildflowgraph(d['lookup_in_type_where_'+attr])
            return funcdesc.cachedgraph(attr, builder=builder)
        else:
            return funcdesc.cachedgraph(None)

    def event(self, bookkeeper, what, x):
        from pypy.objspace.std import typeobject
        from pypy.interpreter import baseobjspace, module
        if what == "classdef_setup" and issubclass(x.classdesc.pyobj, baseobjspace.W_Root):
            classdesc = x.classdesc
            cls = classdesc.pyobj
            # Module is weird in python3! it's the only builtin type where you
            # can change the __class__ of an object, therefore the lookup cache
            # is going to give wrong results, as the new class might override
            # things differently
            if (getattr(cls, "typedef", None) is None or
                    cls.user_overridden_class or
                    issubclass(cls, module.Module)):
                set_attribute(classdesc, None)
                return
            w_type = self.space.gettypeobject(cls.typedef)
            if w_type.is_heaptype() or w_type.is_cpytype():
                set_attribute(classdesc, None)
                return
            if '_static_lookup_cache' not in cls.__dict__:
                set_attribute(classdesc, StaticLookupCache())
                assert '_static_lookup_cache' in cls.__dict__
            else:
                assert 0, "should not be possible"
            self.pypytypes[cls] = w_type
            clsdef = bookkeeper.getuniqueclassdef(StaticLookupCache)
            for attr in self.lookups:
                cached = "cached_%s" % attr
                w_value = w_type._lookup(attr)
                setattr(cls._static_lookup_cache, cached, w_value)
                source = InstanceSource(bookkeeper, cls._static_lookup_cache)
                clsdef.add_source_for_attribute(cached, source)
        if isinstance(x, typeobject.W_TypeObject):
            clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject)
            self.types_w.add(x)
            #print "TYPE", x
            space = self.space
            w_moduletype = space.type(space.sys)
            for attr in self.lookups_where:
                if not (x.is_heaptype() or x.is_cpytype() or
                        space.issubtype_w(x, w_moduletype)):
                    cached = "cached_where_%s" % attr
                    setattr(x, cached, x._lookup_where(attr))
                    source = InstanceSource(bookkeeper, x)
                    clsdef.add_source_for_attribute(cached, source)
        return

class StaticLookupCache(object):
    pass

CACHED_LOOKUP = """
def lookup_%(attr)s(space, w_obj, name):
    cache = w_obj._static_lookup_cache
    if cache is None:
        w_type = space.type(w_obj)
        return w_type.lookup("%(attr)s")
    return cache.cached_%(attr)s
"""

CACHED_LOOKUP_IN_TYPE_WHERE = """
def lookup_in_type_where_%(attr)s(space, w_type, name):
    if not w_type.is_heaptype() and not w_type.is_cpytype():
        return w_type.cached_where_%(attr)s
    return w_type.lookup_where("%(attr)s")
"""