pypy-effect-analysis / pypy / jit / metainterp / executor.py

  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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
"""This implements pyjitpl's execution of operations.
"""

import py
from pypy.rpython.lltypesystem import lltype, llmemory, rstr
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask
from pypy.rlib.unroll import unrolling_iterable
from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr
from pypy.jit.metainterp.history import INT, REF, FLOAT, VOID, AbstractDescr
from pypy.jit.metainterp import resoperation
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.blackhole import BlackholeInterpreter, NULL

# ____________________________________________________________

def do_call(cpu, metainterp, argboxes, descr):
    assert metainterp is not None
    # count the number of arguments of the different types
    count_i = count_r = count_f = 0
    for i in range(1, len(argboxes)):
        type = argboxes[i].type
        if   type == INT:   count_i += 1
        elif type == REF:   count_r += 1
        elif type == FLOAT: count_f += 1
    # allocate lists for each type that has at least one argument
    if count_i: args_i = [0] * count_i
    else:       args_i = None
    if count_r: args_r = [NULL] * count_r
    else:       args_r = None
    if count_f: args_f = [0.0] * count_f
    else:       args_f = None
    # fill in the lists
    count_i = count_r = count_f = 0
    for i in range(1, len(argboxes)):
        box = argboxes[i]
        if   box.type == INT:
            args_i[count_i] = box.getint()
            count_i += 1
        elif box.type == REF:
            args_r[count_r] = box.getref_base()
            count_r += 1
        elif box.type == FLOAT:
            args_f[count_f] = box.getfloat()
            count_f += 1
    # get the function address as an integer
    func = argboxes[0].getint()
    # do the call using the correct function from the cpu
    rettype = descr.get_return_type()
    if rettype == INT:
        try:
            result = cpu.bh_call_i(func, descr, args_i, args_r, args_f)
        except Exception, e:
            metainterp.execute_raised(e)
            result = 0
        return BoxInt(result)
    if rettype == REF:
        try:
            result = cpu.bh_call_r(func, descr, args_i, args_r, args_f)
        except Exception, e:
            metainterp.execute_raised(e)
            result = NULL
        return BoxPtr(result)
    if rettype == FLOAT:
        try:
            result = cpu.bh_call_f(func, descr, args_i, args_r, args_f)
        except Exception, e:
            metainterp.execute_raised(e)
            result = 0.0
        return BoxFloat(result)
    if rettype == VOID:
        try:
            cpu.bh_call_v(func, descr, args_i, args_r, args_f)
        except Exception, e:
            metainterp.execute_raised(e)
        return None
    raise AssertionError("bad rettype")

do_call_loopinvariant = do_call
do_call_may_force = do_call

def do_call_c(cpu, metainterp, argboxes, descr):
    raise NotImplementedError("Should never be called directly")

def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getref_base()
    index = indexbox.getint()
    if arraydescr.is_array_of_pointers():
        return BoxPtr(cpu.bh_getarrayitem_gc_r(arraydescr, array, index))
    elif arraydescr.is_array_of_floats():
        return BoxFloat(cpu.bh_getarrayitem_gc_f(arraydescr, array, index))
    else:
        return BoxInt(cpu.bh_getarrayitem_gc_i(arraydescr, array, index))

def do_getarrayitem_raw(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getint()
    index = indexbox.getint()
    assert not arraydescr.is_array_of_pointers()
    if arraydescr.is_array_of_floats():
        return BoxFloat(cpu.bh_getarrayitem_raw_f(arraydescr, array, index))
    else:
        return BoxInt(cpu.bh_getarrayitem_raw_i(arraydescr, array, index))

def do_setarrayitem_gc(cpu, _, arraybox, indexbox, itembox, arraydescr):
    array = arraybox.getref_base()
    index = indexbox.getint()
    if arraydescr.is_array_of_pointers():
        cpu.bh_setarrayitem_gc_r(arraydescr, array, index,
                                 itembox.getref_base())
    elif arraydescr.is_array_of_floats():
        cpu.bh_setarrayitem_gc_f(arraydescr, array, index, itembox.getfloat())
    else:
        cpu.bh_setarrayitem_gc_i(arraydescr, array, index, itembox.getint())

def do_setarrayitem_raw(cpu, _, arraybox, indexbox, itembox, arraydescr):
    array = arraybox.getint()
    index = indexbox.getint()
    assert not arraydescr.is_array_of_pointers()
    if arraydescr.is_array_of_floats():
        cpu.bh_setarrayitem_raw_f(arraydescr, array, index, itembox.getfloat())
    else:
        cpu.bh_setarrayitem_raw_i(arraydescr, array, index, itembox.getint())

def do_getfield_gc(cpu, _, structbox, fielddescr):
    struct = structbox.getref_base()
    if fielddescr.is_pointer_field():
        return BoxPtr(cpu.bh_getfield_gc_r(struct, fielddescr))
    elif fielddescr.is_float_field():
        return BoxFloat(cpu.bh_getfield_gc_f(struct, fielddescr))
    else:
        return BoxInt(cpu.bh_getfield_gc_i(struct, fielddescr))

def do_getfield_raw(cpu, _, structbox, fielddescr):
    check_descr(fielddescr)
    struct = structbox.getint()
    if fielddescr.is_pointer_field():
        return BoxPtr(cpu.bh_getfield_raw_r(struct, fielddescr))
    elif fielddescr.is_float_field():
        return BoxFloat(cpu.bh_getfield_raw_f(struct, fielddescr))
    else:
        return BoxInt(cpu.bh_getfield_raw_i(struct, fielddescr))

def do_setfield_gc(cpu, _, structbox, itembox, fielddescr):
    struct = structbox.getref_base()
    if fielddescr.is_pointer_field():
        cpu.bh_setfield_gc_r(struct, fielddescr, itembox.getref_base())
    elif fielddescr.is_float_field():
        cpu.bh_setfield_gc_f(struct, fielddescr, itembox.getfloat())
    else:
        cpu.bh_setfield_gc_i(struct, fielddescr, itembox.getint())

def do_setfield_raw(cpu, _, structbox, itembox, fielddescr):
    struct = structbox.getint()
    if fielddescr.is_pointer_field():
        cpu.bh_setfield_raw_r(struct, fielddescr, itembox.getref_base())
    elif fielddescr.is_float_field():
        cpu.bh_setfield_raw_f(struct, fielddescr, itembox.getfloat())
    else:
        cpu.bh_setfield_raw_i(struct, fielddescr, itembox.getint())

def exec_new_with_vtable(cpu, clsbox):
    from pypy.jit.codewriter import heaptracker
    vtable = clsbox.getint()
    descr = heaptracker.vtable2descr(cpu, vtable)
    return cpu.bh_new_with_vtable(descr, vtable)

def do_new_with_vtable(cpu, _, clsbox):
    return BoxPtr(exec_new_with_vtable(cpu, clsbox))

def do_int_add_ovf(cpu, metainterp, box1, box2):
    # the overflow operations can be called without a metainterp, if an
    # overflow cannot occur
    a = box1.getint()
    b = box2.getint()
    try:
        z = ovfcheck(a + b)
    except OverflowError:
        assert metainterp is not None
        metainterp.execute_raised(OverflowError(), constant=True)
        z = 0
    return BoxInt(z)

def do_int_sub_ovf(cpu, metainterp, box1, box2):
    a = box1.getint()
    b = box2.getint()
    try:
        z = ovfcheck(a - b)
    except OverflowError:
        assert metainterp is not None
        metainterp.execute_raised(OverflowError(), constant=True)
        z = 0
    return BoxInt(z)

def do_int_mul_ovf(cpu, metainterp, box1, box2):
    a = box1.getint()
    b = box2.getint()
    try:
        z = ovfcheck(a * b)
    except OverflowError:
        assert metainterp is not None
        metainterp.execute_raised(OverflowError(), constant=True)
        z = 0
    return BoxInt(z)

def do_same_as(cpu, _, box):
    return box.clonebox()

def do_copystrcontent(cpu, _, srcbox, dstbox,
                      srcstartbox, dststartbox, lengthbox):
    src = srcbox.getref(lltype.Ptr(rstr.STR))
    dst = dstbox.getref(lltype.Ptr(rstr.STR))
    srcstart = srcstartbox.getint()
    dststart = dststartbox.getint()
    length = lengthbox.getint()
    rstr.copy_string_contents(src, dst, srcstart, dststart, length)

def do_copyunicodecontent(cpu, _, srcbox, dstbox,
                          srcstartbox, dststartbox, lengthbox):
    src = srcbox.getref(lltype.Ptr(rstr.UNICODE))
    dst = dstbox.getref(lltype.Ptr(rstr.UNICODE))
    srcstart = srcstartbox.getint()
    dststart = dststartbox.getint()
    length = lengthbox.getint()
    rstr.copy_unicode_contents(src, dst, srcstart, dststart, length)

# ____________________________________________________________

##def do_force_token(cpu):
##    raise NotImplementedError

##def do_virtual_ref(cpu, box1, box2):
##    raise NotImplementedError

##def do_virtual_ref_finish(cpu, box1, box2):
##    raise NotImplementedError

##def do_debug_merge_point(cpu, box1):
##    from pypy.jit.metainterp.warmspot import get_stats
##    loc = box1._get_str()
##    get_stats().add_merge_point_location(loc)

# ____________________________________________________________


def _make_execute_list():
    if 0:     # enable this to trace calls to do_xxx
        def wrap(fn):
            def myfn(*args):
                print '<<<', fn.__name__
                try:
                    return fn(*args)
                finally:
                    print fn.__name__, '>>>'
            return myfn
    else:
        def wrap(fn):
            return fn
    #
    execute_by_num_args = {}
    for key, value in rop.__dict__.items():
        if not key.startswith('_'):
            if (rop._FINAL_FIRST <= value <= rop._FINAL_LAST or
                rop._GUARD_FIRST <= value <= rop._GUARD_LAST):
                continue
            # find which list to store the operation in, based on num_args
            num_args = resoperation.oparity[value]
            withdescr = resoperation.opwithdescr[value]
            dictkey = num_args, withdescr
            if dictkey not in execute_by_num_args:
                execute_by_num_args[dictkey] = [None] * (rop._LAST+1)
            execute = execute_by_num_args[dictkey]
            #
            if execute[value] is not None:
                raise AssertionError("duplicate entry for op number %d"% value)
            #
            # Fish for a way for the pyjitpl interpreter to delegate
            # really running the operation to the blackhole interpreter
            # or directly to the cpu.  First try the do_xxx() functions
            # explicitly encoded above:
            name = 'do_' + key.lower()
            if name in globals():
                execute[value] = globals()[name]
                continue
            #
            # Maybe the same without the _PURE suffix?
            if key.endswith('_PURE'):
                key = key[:-5]
                name = 'do_' + key.lower()
                if name in globals():
                    execute[value] = globals()[name]
                    continue
            #
            # If missing, fallback to the bhimpl_xxx() method of the
            # blackhole interpreter.  This only works if there is a
            # method of the exact same name and it accepts simple
            # parameters.
            name = 'bhimpl_' + key.lower()
            if hasattr(BlackholeInterpreter, name):
                func = make_execute_function_with_boxes(
                    key.lower(),
                    getattr(BlackholeInterpreter, name).im_func)
                if func is not None:
                    execute[value] = func
                    continue
            if value in (rop.FORCE_TOKEN,
                         rop.CALL_ASSEMBLER,
                         rop.COND_CALL_GC_WB,
                         rop.DEBUG_MERGE_POINT,
                         rop.JIT_DEBUG,
                         rop.SETARRAYITEM_RAW,
                         ):      # list of opcodes never executed by pyjitpl
                continue
            raise AssertionError("missing %r" % (key,))
    return execute_by_num_args

def make_execute_function_with_boxes(name, func):
    # Make a wrapper for 'func'.  The func is a simple bhimpl_xxx function
    # from the BlackholeInterpreter class.  The wrapper is a new function
    # that receives and returns boxed values.
    for argtype in func.argtypes:
        if argtype not in ('i', 'r', 'f', 'd', 'cpu'):
            return None
    if list(func.argtypes).count('d') > 1:
        return None
    if func.resulttype not in ('i', 'r', 'f', None):
        return None
    argtypes = unrolling_iterable(func.argtypes)
    resulttype = func.resulttype
    #
    def do(cpu, _, *argboxes):
        newargs = ()
        for argtype in argtypes:
            if argtype == 'cpu':
                value = cpu
            elif argtype == 'd':
                value = argboxes[-1]
                assert isinstance(value, AbstractDescr)
                argboxes = argboxes[:-1]
            else:
                argbox = argboxes[0]
                argboxes = argboxes[1:]
                if argtype == 'i':   value = argbox.getint()
                elif argtype == 'r': value = argbox.getref_base()
                elif argtype == 'f': value = argbox.getfloat()
            newargs = newargs + (value,)
        assert not argboxes
        #
        result = func(*newargs)
        #
        if resulttype == 'i': return BoxInt(result)
        if resulttype == 'r': return BoxPtr(result)
        if resulttype == 'f': return BoxFloat(result)
        return None
    #
    do.func_name = 'do_' + name
    return do

def get_execute_funclist(num_args, withdescr):
    # workaround, similar to the next one
    return EXECUTE_BY_NUM_ARGS[num_args, withdescr]
get_execute_funclist._annspecialcase_ = 'specialize:memo'

def get_execute_function(opnum, num_args, withdescr):
    # workaround for an annotation limitation: putting this code in
    # a specialize:memo function makes sure the following line is
    # constant-folded away.  Only works if opnum and num_args are
    # constants, of course.
    func = EXECUTE_BY_NUM_ARGS[num_args, withdescr][opnum]
    assert func is not None, "EXECUTE_BY_NUM_ARGS[%s, %s][%s]" % (
        num_args, withdescr, resoperation.opname[opnum])
    return func
get_execute_function._annspecialcase_ = 'specialize:memo'

def has_descr(opnum):
    # workaround, similar to the previous one
    return resoperation.opwithdescr[opnum]
has_descr._annspecialcase_ = 'specialize:memo'


def execute(cpu, metainterp, opnum, descr, *argboxes):
    # only for opnums with a fixed arity
    num_args = len(argboxes)
    withdescr = has_descr(opnum)
    if withdescr:
        check_descr(descr)
        argboxes = argboxes + (descr,)
    else:
        assert descr is None
    func = get_execute_function(opnum, num_args, withdescr)
    return func(cpu, metainterp, *argboxes)  # note that the 'argboxes' tuple
                                             # optionally ends with the descr
execute._annspecialcase_ = 'specialize:arg(2)'

def execute_varargs(cpu, metainterp, opnum, argboxes, descr):
    # only for opnums with a variable arity (calls, typically)
    check_descr(descr)
    func = get_execute_function(opnum, -1, True)
    return func(cpu, metainterp, argboxes, descr)
execute_varargs._annspecialcase_ = 'specialize:arg(2)'


def execute_nonspec(cpu, metainterp, opnum, argboxes, descr=None):
    arity = resoperation.oparity[opnum]
    assert arity == -1 or len(argboxes) == arity
    if resoperation.opwithdescr[opnum]:
        check_descr(descr)
        if arity == -1:
            func = get_execute_funclist(-1, True)[opnum]
            return func(cpu, metainterp, argboxes, descr)
        if arity == 0:
            func = get_execute_funclist(0, True)[opnum]
            return func(cpu, metainterp, descr)
        if arity == 1:
            func = get_execute_funclist(1, True)[opnum]
            return func(cpu, metainterp, argboxes[0], descr)
        if arity == 2:
            func = get_execute_funclist(2, True)[opnum]
            return func(cpu, metainterp, argboxes[0], argboxes[1], descr)
        if arity == 3:
            func = get_execute_funclist(3, True)[opnum]
            return func(cpu, metainterp, argboxes[0], argboxes[1], argboxes[2],
                        descr)
    else:
        assert descr is None
        if arity == 1:
            func = get_execute_funclist(1, False)[opnum]
            return func(cpu, metainterp, argboxes[0])
        if arity == 2:
            func = get_execute_funclist(2, False)[opnum]
            return func(cpu, metainterp, argboxes[0], argboxes[1])
        if arity == 3:
            func = get_execute_funclist(3, False)[opnum]
            return func(cpu, metainterp, argboxes[0], argboxes[1], argboxes[2])
        if arity == 5:    # copystrcontent, copyunicodecontent
            func = get_execute_funclist(5, False)[opnum]
            return func(cpu, metainterp, argboxes[0], argboxes[1],
                        argboxes[2], argboxes[3], argboxes[4])
    raise NotImplementedError


EXECUTE_BY_NUM_ARGS = _make_execute_list()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.