File: framestate.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 (148 lines) | stat: -rw-r--r-- 5,423 bytes parent folder | download | duplicates (2)
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
from rpython.flowspace.model import Variable, Constant, FSException
from rpython.rlib.unroll import SpecTag

def _copy(v):
    from rpython.flowspace.flowcontext import FlowSignal
    if isinstance(v, Variable):
        return Variable(v)
    elif isinstance(v, FlowSignal):
        vars = [_copy(var) for var in v.args]
        return v.rebuild(*vars)
    else:
        return v

def _union(seq1, seq2):
    return [union(v1, v2) for v1, v2 in zip(seq1, seq2)]


class FrameState(object):
    def __init__(self, locals_w, stack, last_exception, blocklist, next_offset):
        self.locals_w = locals_w
        self.stack = stack
        self.last_exception = last_exception
        self.blocklist = blocklist
        self.next_offset = next_offset
        self._mergeable = None

    @property
    def mergeable(self):
        from rpython.flowspace.flowcontext import FlowSignal
        if self._mergeable is not None:
            return self._mergeable

        self._mergeable = data = self.locals_w + recursively_flatten(self.stack)
        if self.last_exception is None:
            data.append(Constant(None))
            data.append(Constant(None))
        else:
            data.append(self.last_exception.w_type)
            data.append(self.last_exception.w_value)
        return data

    def copy(self):
        "Make a copy of this state in which all Variables are fresh."
        exc = self.last_exception
        if exc is not None:
            exc = FSException(_copy(exc.w_type), _copy(exc.w_value))
        return FrameState(map(_copy, self.locals_w), map(_copy, self.stack),
                exc, self.blocklist, self.next_offset)

    def getvariables(self):
        return [w for w in self.mergeable if isinstance(w, Variable)]

    def matches(self, other):
        """Two states match if they only differ by using different Variables
        at the same place"""
        # safety check, don't try to compare states with different
        # nonmergeable states
        assert self.blocklist == other.blocklist
        assert self.next_offset == other.next_offset
        for w1, w2 in zip(self.mergeable, other.mergeable):
            if not (w1 == w2 or (isinstance(w1, Variable) and
                                 isinstance(w2, Variable))):
                return False
        return True

    def _exc_args(self):
        if self.last_exception is None:
            return [Constant(None), Constant(None)]
        else:
            return [self.last_exception.w_type,
                    self.last_exception.w_value]

    def union(self, other):
        """Compute a state that is at least as general as both self and other.
           A state 'a' is more general than a state 'b' if all Variables in 'b'
           are also Variables in 'a', but 'a' may have more Variables.
        """
        try:
            locals = _union(self.locals_w, other.locals_w)
            stack = _union(self.stack, other.stack)
            if self.last_exception is None and other.last_exception is None:
                exc = None
            else:
                args1 = self._exc_args()
                args2 = other._exc_args()
                exc = FSException(union(args1[0], args2[0]),
                        union(args1[1], args2[1]))
        except UnionError:
            return None
        return FrameState(locals, stack, exc, self.blocklist, self.next_offset)

    def getoutputargs(self, targetstate):
        "Return the output arguments needed to link self to targetstate."
        result = []
        mergeable = self.mergeable
        for i, w_target in enumerate(targetstate.mergeable):
            if isinstance(w_target, Variable):
                result.append(mergeable[i])
        return result

class UnionError(Exception):
    "The two states should be merged."


def union(w1, w2):
    "Union of two variables or constants."
    from rpython.flowspace.flowcontext import FlowSignal
    if w1 == w2:
        return w1
    if w1 is None or w2 is None:
        return None  # if w1 or w2 is an undefined local, we "kill" the value
                     # coming from the other path and return an undefined local
    if isinstance(w1, Variable) or isinstance(w2, Variable):
        return Variable()  # new fresh Variable
    if isinstance(w1, Constant) and isinstance(w2, Constant):
        if isinstance(w1.value, SpecTag) or isinstance(w2.value, SpecTag):
            raise UnionError
        else:
            return Variable()  # generalize different constants
    if isinstance(w1, FlowSignal) and isinstance(w2, FlowSignal):
        if type(w1) is not type(w2):
            raise UnionError
        vars = [union(v1, v2) for v1, v2 in zip(w1.args, w2.args)]
        return w1.rebuild(*vars)
    if isinstance(w1, FlowSignal) or isinstance(w2, FlowSignal):
        raise UnionError
    raise TypeError('union of %r and %r' % (w1.__class__.__name__,
                                            w2.__class__.__name__))


def recursively_flatten(lst):
    from rpython.flowspace.flowcontext import FlowSignal
    if not lst:
        return lst
    i = -1
    for i in range(len(lst)):
        if isinstance(lst[i], FlowSignal):
            break
    else:
        return lst
    lst = lst[:]
    while i < len(lst):
        unroller = lst[i]
        if not isinstance(unroller, FlowSignal):
            i += 1
        else:
            lst[i:i + 1] = unroller.args
    return lst