File: instruction.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (269 lines) | stat: -rw-r--r-- 9,231 bytes parent folder | download | duplicates (4)
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
LOC_REG       = 0
LOC_ESP_PLUS  = 1
LOC_EBP_PLUS  = 2
LOC_EBP_MINUS = 3
LOC_MASK      = 0x03
LOC_NOWHERE   = LOC_REG | 0

# x86-32 registers sometimes used to pass arguments when gcc optimizes
# a function's calling convention
ARGUMENT_REGISTERS_32 = ('%eax', '%edx', '%ecx')

# x86-64 registers used to pass arguments
ARGUMENT_REGISTERS_64 = ('%rdi', '%rsi', '%rdx', '%rcx', '%r8', '%r9')


def frameloc_esp(offset, wordsize):
    assert offset >= 0
    assert offset % wordsize == 0
    if wordsize == 8:    # in this case, there are 3 null bits, but we
        offset >>= 1     # only need 2 of them
    return LOC_ESP_PLUS | offset

def frameloc_ebp(offset, wordsize):
    assert offset % wordsize == 0
    if wordsize == 8:    # in this case, there are 3 null bits, but we
        offset >>= 1     # only need 2 of them
    if offset >= 0:
        return LOC_EBP_PLUS | offset
    else:
        return LOC_EBP_MINUS | (-offset)


class SomeNewValue(object):
    def __repr__(self):
        return 'somenewvalue'
somenewvalue = SomeNewValue()

class LocalVar(object):
    # A local variable location at position 'ofs_from_frame_end',
    # which is counted from the end of the stack frame (so it is always
    # negative, unless it refers to arguments of the current function).
    def __init__(self, ofs_from_frame_end, hint=None):
        self.ofs_from_frame_end = ofs_from_frame_end
        self.hint = hint

    def __repr__(self):
        return '<%+d;%s>' % (self.ofs_from_frame_end, self.hint or 'e*p')

    def __hash__(self):
        return hash(self.ofs_from_frame_end)

    def __cmp__(self, other):
        if isinstance(other, LocalVar):
            return cmp(self.ofs_from_frame_end, other.ofs_from_frame_end)
        else:
            return 1

    def getlocation(self, framesize, uses_frame_pointer, wordsize):
        if (self.hint == 'esp' or not uses_frame_pointer
            or self.ofs_from_frame_end % 1 != 0):
            # try to use esp-relative addressing
            ofs_from_esp = framesize + self.ofs_from_frame_end
            if ofs_from_esp % 1 == 0:
                return frameloc_esp(int(ofs_from_esp), wordsize)
            # we can get an odd value if the framesize is marked as bogus
            # by visit_andl()
        assert uses_frame_pointer
        ofs_from_ebp = self.ofs_from_frame_end + wordsize
        return frameloc_ebp(ofs_from_ebp, wordsize)


class Insn(object):
    _args_ = []
    _locals_ = []
    hack = None

    def __repr__(self):
        return '%s(%s) --- %r' % (self.__class__.__name__,
                           ', '.join([str(getattr(self, name))
                                      for name in self._args_]),
                                  self.hack)
    def requestgcroots(self, tracker):
        return {}

    def source_of(self, localvar, tag):
        if tag is None:
            if self.hack is None:
                self.hack = set()
            self.hack.add(localvar)
        return localvar

    def all_sources_of(self, localvar):
        return [localvar]

class InsnCondJump(Insn):     # only for debugging; not used internally
    _args_ = ['label']
    def __init__(self, label):
        self.label = label

class Label(Insn):
    _args_ = ['label', 'lineno']
    def __init__(self, label, lineno):
        self.label = label
        self.lineno = lineno
        self.previous_insns = []   # all insns that jump (or fallthrough) here

class InsnFunctionStart(Insn):
    _args_ = ['arguments']
    framesize = 0
    previous_insns = ()
    def __init__(self, registers, wordsize):
        self.arguments = {}
        for reg in registers:
            self.arguments[reg] = somenewvalue
        self.wordsize = wordsize

    def source_of(self, localvar, tag):
        if localvar not in self.arguments:
            if self.wordsize == 4 and localvar in ARGUMENT_REGISTERS_32:
                # xxx this might show a bug in trackgcroot.py failing to
                # figure out which instruction stored a value in these
                # registers.  However, this case also occurs when the
                # the function's calling convention was optimized by gcc:
                # the 3 registers above are then used to pass arguments
                pass
            elif self.wordsize == 8 and localvar in ARGUMENT_REGISTERS_64:
                # this is normal: these registers are always used to
                # pass arguments
                pass
            else:
                assert (isinstance(localvar, LocalVar) and
                        localvar.ofs_from_frame_end > 0), (
                    "must come from an argument to the function, got %r" %
                    (localvar,))
            self.arguments[localvar] = somenewvalue
        return self.arguments[localvar]

    def all_sources_of(self, localvar):
        return []

class InsnSetLocal(Insn):
    _args_ = ['target', 'sources']
    _locals_ = ['target', 'sources']

    def __init__(self, target, sources=()):
        self.target = target
        self.sources = sources

    def source_of(self, localvar, tag):
        if localvar == self.target:
            return somenewvalue
        return Insn.source_of(self, localvar, tag)

    def all_sources_of(self, localvar):
        if localvar == self.target:
            return self.sources
        return [localvar]

class InsnCopyLocal(Insn):
    _args_ = ['source', 'target']
    _locals_ = ['source', 'target']

    def __init__(self, source, target):
        self.source = source
        self.target = target

    def source_of(self, localvar, tag):
        if localvar == self.target:
            return self.source
        return Insn.source_of(self, localvar, tag)

    def all_sources_of(self, localvar):
        if localvar == self.target:
            return [self.source]
        return [localvar]

class InsnStackAdjust(Insn):
    _args_ = ['delta']
    def __init__(self, delta):
        #assert delta % 4 == 0 --- but not really, gcc generates strange code
        self.delta = delta

class InsnCannotFollowEsp(InsnStackAdjust):
    def __init__(self):
        self.delta = -7.25     # use this non-integer value as a marker

class InsnPushed(InsnStackAdjust):
    pass

class InsnStop(Insn):
    _args_ = ['reason']
    def __init__(self, reason='?'):
        self.reason = reason

class InsnRet(InsnStop):
    _args_ = []
    framesize = 0
    def __init__(self, registers):
        self.registers = registers

    def requestgcroots(self, tracker):
        # no need to track the value of these registers in the caller
        # function if we are flagged as a "bottom" function (a callback
        # from C code, or pypy_main_function())
        if tracker.is_stack_bottom:
            return {}
        else:
            return dict(zip(self.registers, self.registers))

class InsnCall(Insn):
    _args_ = ['lineno', 'name', 'gcroots']
    def __init__(self, name, lineno):
        # 'gcroots' is a dict built by side-effect during the call to
        # FunctionGcRootTracker.trackgcroots().  Its meaning is as
        # follows: the keys are the locations that contain gc roots
        # (register names or LocalVar instances).  The value
        # corresponding to a key is the "tag", which is None for a
        # normal gc root, or else the name of a callee-saved register.
        # In the latter case it means that this is only a gc root if the
        # corresponding register in the caller was really containing a
        # gc pointer.  A typical example:
        #
        #   InsnCall({LocalVar(-8)': None,
        #             '%esi': '%esi',
        #             LocalVar(-12)': '%ebx'})
        #
        # means that the value at -8 from the frame end is a gc root
        # across this call; that %esi is a gc root if it was in the
        # caller (typically because %esi is not modified at all in the
        # current function); and that the value at -12 from the frame
        # end is a gc root if %ebx was a gc root in the caller
        # (typically because the current function saves and restores
        # %ebx from there in the prologue and epilogue).
        self.gcroots = {}
        self.lineno = lineno
        self.name = name

    def source_of(self, localvar, tag):
        tag1 = self.gcroots.setdefault(localvar, tag)
        assert tag1 == tag, (
            "conflicting entries for\n%s.gcroots[%s]:\n%r and %r" % (
            self, localvar, tag1, tag))
        return localvar

    def all_sources_of(self, localvar):
        return [localvar]

class InsnGCROOT(Insn):
    _args_ = ['loc']
    _locals_ = ['loc']
    def __init__(self, loc):
        self.loc = loc
    def requestgcroots(self, tracker):
        return {self.loc: None}

class InsnPrologue(Insn):
    def __init__(self, wordsize):
        self.wordsize = wordsize
    def __setattr__(self, attr, value):
        if attr == 'framesize':
            assert value == self.wordsize, (
                "unrecognized function prologue - "
                "only supports push %ebp; movl %esp, %ebp")
        Insn.__setattr__(self, attr, value)

class InsnEpilogue(Insn):
    def __init__(self, framesize=None):
        if framesize is not None:
            self.framesize = framesize