File: executor.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 (588 lines) | stat: -rw-r--r-- 22,379 bytes parent folder | download
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
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
"""This implements pyjitpl's execution of operations.
"""

from rpython.rtyper.lltypesystem import lltype, rstr, llmemory
from rpython.rlib.rarithmetic import ovfcheck, r_longlong, is_valid_int
from rpython.rlib.unroll import unrolling_iterable
from rpython.rlib.objectmodel import specialize
from rpython.jit.metainterp.history import check_descr
from rpython.jit.metainterp.history import INT, REF, FLOAT, VOID, AbstractDescr
from rpython.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr
from rpython.jit.metainterp import resoperation
from rpython.jit.metainterp.resoperation import rop, opname
from rpython.jit.metainterp.blackhole import BlackholeInterpreter, NULL
from rpython.jit.codewriter import longlong

# ____________________________________________________________

@specialize.arg(4)
def _do_call(cpu, metainterp, argboxes, descr, rettype):
    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 = [longlong.ZEROF] * 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.getfloatstorage()
            count_f += 1
    # get the function address as an integer
    func = argboxes[0].getint()
    # do the call using the correct function from the cpu
    if rettype == INT:
        try:
            result = cpu.bh_call_i(func, args_i, args_r, args_f, descr)
        except Exception as e:
            metainterp.execute_raised(e)
            result = 0
        return result
    if rettype == REF:
        try:
            result = cpu.bh_call_r(func, args_i, args_r, args_f, descr)
        except Exception as e:
            metainterp.execute_raised(e)
            result = NULL
        return result
    if rettype == FLOAT:
        try:
            result = cpu.bh_call_f(func, args_i, args_r, args_f, descr)
        except Exception as e:
            metainterp.execute_raised(e)
            result = longlong.ZEROF
        return result
    if rettype == VOID:
        try:
            cpu.bh_call_v(func, args_i, args_r, args_f, descr)
        except Exception as e:
            metainterp.execute_raised(e)
        return None
    raise AssertionError("bad rettype")

def new_do_call(rettype):
    def do_call(cpu, metainterp, argboxes, descr):
        return _do_call(cpu, metainterp, argboxes, descr, rettype)
    do_call.func_name = "do_call_" + rettype
    return do_call

do_call_r = new_do_call("r")
do_call_i = new_do_call("i")
do_call_f = new_do_call("f")
do_call_n = new_do_call("v")
do_call_loopinvariant_r = do_call_r
do_call_loopinvariant_i = do_call_i
do_call_loopinvariant_f = do_call_f
do_call_loopinvariant_n = do_call_n
do_call_may_force_r = do_call_r
do_call_may_force_i = do_call_i
do_call_may_force_f = do_call_f
do_call_may_force_n = do_call_n

def do_cond_call(cpu, metainterp, argboxes, descr):
    condbox = argboxes[0]
    if condbox.getint():
        do_call_n(cpu, metainterp, argboxes[1:], descr)

def do_cond_call_value_i(cpu, metainterp, argboxes, descr):
    value = argboxes[0].getint()
    if value == 0:
        value = do_call_i(cpu, metainterp, argboxes[1:], descr)
    return value

def do_cond_call_value_r(cpu, metainterp, argboxes, descr):
    value = argboxes[0].getref_base()
    if not value:
        value = do_call_r(cpu, metainterp, argboxes[1:], descr)
    return value

def do_getarrayitem_gc_i(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getref_base()
    index = indexbox.getint()
    return cpu.bh_getarrayitem_gc_i(array, index, arraydescr)

def do_getarrayitem_gc_r(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getref_base()
    index = indexbox.getint()
    return cpu.bh_getarrayitem_gc_r(array, index, arraydescr)

def do_getarrayitem_gc_f(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getref_base()
    index = indexbox.getint()
    return cpu.bh_getarrayitem_gc_f(array, index, arraydescr)

def do_getarrayitem_raw_i(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getint()
    index = indexbox.getint()
    return cpu.bh_getarrayitem_raw_i(array, index, arraydescr)

def do_getarrayitem_raw_f(cpu, _, arraybox, indexbox, arraydescr):
    array = arraybox.getint()
    index = indexbox.getint()
    return cpu.bh_getarrayitem_raw_f(array, index, arraydescr)

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(array, index, itembox.getref_base(),
                                 arraydescr)
    elif arraydescr.is_array_of_floats():
        cpu.bh_setarrayitem_gc_f(array, index, itembox.getfloatstorage(),
                                 arraydescr)
    else:
        cpu.bh_setarrayitem_gc_i(array, index, itembox.getint(), arraydescr)

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(array, index, itembox.getfloatstorage(),
                                  arraydescr)
    else:
        cpu.bh_setarrayitem_raw_i(array, index, itembox.getint(), arraydescr)

def do_getinteriorfield_gc(cpu, _, arraybox, indexbox, descr):
    raise Exception("implement me")
    xxxx
    array = arraybox.getref_base()
    index = indexbox.getint()
    if descr.is_pointer_field():
        return BoxPtr(cpu.bh_getinteriorfield_gc_r(array, index, descr))
    elif descr.is_float_field():
        return BoxFloat(cpu.bh_getinteriorfield_gc_f(array, index, descr))
    else:
        return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr))

def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, descr):
    array = arraybox.getref_base()
    index = indexbox.getint()
    if descr.is_pointer_field():
        cpu.bh_setinteriorfield_gc_r(array, index, valuebox.getref_base(),
                                     descr)
    elif descr.is_float_field():
        cpu.bh_setinteriorfield_gc_f(array, index, valuebox.getfloatstorage(),
                                     descr)
    else:
        cpu.bh_setinteriorfield_gc_i(array, index, valuebox.getint(), descr)

def do_getfield_gc_i(cpu, _, structbox, fielddescr):
    struct = structbox.getref_base()
    return cpu.bh_getfield_gc_i(struct, fielddescr)

def do_getfield_gc_r(cpu, _, structbox, fielddescr):
    struct = structbox.getref_base()
    return cpu.bh_getfield_gc_r(struct, fielddescr)

def do_getfield_gc_f(cpu, _, structbox, fielddescr):
    struct = structbox.getref_base()
    return cpu.bh_getfield_gc_f(struct, fielddescr)

def do_getfield_raw_i(cpu, _, structbox, fielddescr):
    check_descr(fielddescr)
    struct = structbox.getint()
    return cpu.bh_getfield_raw_i(struct, fielddescr)

def do_getfield_raw_f(cpu, _, structbox, fielddescr):
    check_descr(fielddescr)
    struct = structbox.getint()
    return cpu.bh_getfield_raw_f(struct, fielddescr)

def do_getfield_raw_r(cpu, _, structbox, fielddescr):
    check_descr(fielddescr)
    struct = structbox.getint()
    return cpu.bh_getfield_raw_r(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, itembox.getref_base(), fielddescr)
    elif fielddescr.is_float_field():
        cpu.bh_setfield_gc_f(struct, itembox.getfloatstorage(), fielddescr)
    else:
        cpu.bh_setfield_gc_i(struct, itembox.getint(), fielddescr)

def do_setfield_raw(cpu, _, structbox, itembox, fielddescr):
    struct = structbox.getint()
    assert not fielddescr.is_pointer_field()
    if fielddescr.is_float_field():
        cpu.bh_setfield_raw_f(struct, itembox.getfloatstorage(), fielddescr)
    else:
        cpu.bh_setfield_raw_i(struct, itembox.getint(), fielddescr)

def do_raw_store(cpu, _, addrbox, offsetbox, valuebox, arraydescr):
    addr = addrbox.getint()
    offset = offsetbox.getint()
    if arraydescr.is_array_of_pointers():
        raise AssertionError("cannot store GC pointers in raw store")
    elif arraydescr.is_array_of_floats():
        cpu.bh_raw_store_f(addr, offset, valuebox.getfloatstorage(),arraydescr)
    else:
        cpu.bh_raw_store_i(addr, offset, valuebox.getint(), arraydescr)

def do_raw_load(cpu, _, addrbox, offsetbox, arraydescr):
    raise Exception("implement me")    
    xxx
    addr = addrbox.getint()
    offset = offsetbox.getint()
    if arraydescr.is_array_of_pointers():
        raise AssertionError("cannot store GC pointers in raw store")
    elif arraydescr.is_array_of_floats():
        return BoxFloat(cpu.bh_raw_load_f(addr, offset, arraydescr))
    else:
        return BoxInt(cpu.bh_raw_load_i(addr, offset, arraydescr))

def exec_new_with_vtable(cpu, descr):
    return cpu.bh_new_with_vtable(descr)

def do_new_with_vtable(cpu, _, clsbox):
    return 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.ovf_flag = True
        z = 0
    return 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.ovf_flag = True
        z = 0
    return 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.ovf_flag = True
        z = 0
    return z

def do_same_as_i(cpu, _, v):
    return v.getint()

def do_same_as_r(cpu, _, v):
    return v.getref_base()

def do_same_as_f(cpu, _, v):
    return v.getfloatstorage()

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_keepalive(cpu, _, x):
    pass

# ____________________________________________________________


def _make_execute_list():
    execute_by_num_args = {}
    for key in opname.values():
        value = getattr(rop, key)
        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[-7:-2] == '_PURE':
                key = key[:-7] + key[-2:]
                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(
                    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_R,
                         rop.CALL_ASSEMBLER_F,
                         rop.CALL_ASSEMBLER_I,
                         rop.CALL_ASSEMBLER_N,
                         rop.INCREMENT_DEBUG_COUNTER,
                         rop.COND_CALL_VALUE_R,
                         rop.COND_CALL_VALUE_I,
                         rop.COND_CALL_GC_WB,
                         rop.COND_CALL_GC_WB_ARRAY,
                         rop.ZERO_ARRAY,
                         rop.DEBUG_MERGE_POINT,
                         rop.JIT_DEBUG,
                         rop.ENTER_PORTAL_FRAME,
                         rop.LEAVE_PORTAL_FRAME,
                         rop.SETARRAYITEM_RAW,
                         rop.SETINTERIORFIELD_RAW,
                         rop.CALL_RELEASE_GIL_I,
                         rop.CALL_RELEASE_GIL_F,
                         rop.CALL_RELEASE_GIL_N,
                         rop.QUASIIMMUT_FIELD,
                         rop.CHECK_MEMORY_ERROR,
                         rop.CALL_MALLOC_NURSERY,
                         rop.CALL_MALLOC_NURSERY_VARSIZE,
                         rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME,
                         rop.NURSERY_PTR_INCREMENT,
                         rop.LABEL,
                         rop.ESCAPE_I,
                         rop.ESCAPE_N,
                         rop.ESCAPE_R,
                         rop.ESCAPE_F,
                         rop.FORCE_SPILL,
                         rop.SAVE_EXC_CLASS,
                         rop.SAVE_EXCEPTION,
                         rop.RESTORE_EXCEPTION,
                         rop.VEC_LOAD_I,
                         rop.VEC_LOAD_F,
                         rop.GC_LOAD_I,
                         rop.GC_LOAD_R,
                         rop.GC_LOAD_F,
                         rop.GC_LOAD_INDEXED_R,
                         rop.VEC_STORE,
                         rop.GC_STORE,
                         rop.GC_STORE_INDEXED,
                         rop.LOAD_FROM_GC_TABLE,
                         ):      # list of opcodes never executed by pyjitpl
                continue
            if rop._VEC_PURE_FIRST <= value <= rop._VEC_PURE_LAST:
                continue

            raise AssertionError("missing %r" % (key,))
    return execute_by_num_args

def make_execute_function(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 boxed values (but returns a non-boxed value).
    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
    argtypes = unrolling_iterable(func.argtypes)
    #
    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.getfloatstorage()
            newargs = newargs + (value,)
        assert not argboxes
        #
        return func(*newargs)
    #
    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)'

@specialize.argtype(0)
def wrap_constant(value):
    if lltype.typeOf(value) == lltype.Signed:
        return ConstInt(value)
    elif isinstance(value, bool):
        return ConstInt(int(value))
    elif lltype.typeOf(value) == longlong.FLOATSTORAGE:
        return ConstFloat(value)
    elif isinstance(value, float):
        return ConstFloat(longlong.getfloatstorage(value))
    else:
        assert lltype.typeOf(value) == llmemory.GCREF
        return ConstPtr(value)

def constant_from_op(op):
    if op.type == 'i':
        return ConstInt(op.getint())
    elif op.type == 'r':
        return ConstPtr(op.getref_base())
    else:
        assert op.type == 'f'
        return ConstFloat(op.getfloatstorage())

unrolled_range = unrolling_iterable(range(rop._LAST))
    
def execute_nonspec_const(cpu, metainterp, opnum, argboxes, descr=None,
                          type='i'):
    for num in unrolled_range:
        if num == opnum:
            return wrap_constant(_execute_arglist(cpu, metainterp, num,
                                                  argboxes, descr))
    assert False

@specialize.arg(2)
def _execute_arglist(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_function(opnum, -1, True)
            if func:
                return func(cpu, metainterp, argboxes, descr)
        if arity == 0:
            func = get_execute_function(opnum, 0, True)
            if func:
                return func(cpu, metainterp, descr)
        if arity == 1:
            func = get_execute_function(opnum, 1, True)
            if func:
                return func(cpu, metainterp, argboxes[0], descr)
        if arity == 2:
            func = get_execute_function(opnum, 2, True)
            if func:
                return func(cpu, metainterp, argboxes[0], argboxes[1], descr)
        if arity == 3:
            func = get_execute_function(opnum, 3, True)
            if func:
                return func(cpu, metainterp, argboxes[0], argboxes[1],
                            argboxes[2], descr)
    else:
        assert descr is None
        if arity == 1:
            func = get_execute_function(opnum, 1, False)
            if func:
                return func(cpu, metainterp, argboxes[0])
        if arity == 2:
            func = get_execute_function(opnum, 2, False)
            if func:
                return func(cpu, metainterp, argboxes[0], argboxes[1])
        if arity == 3:
            func = get_execute_function(opnum, 3, False)
            if func:
                return func(cpu, metainterp, argboxes[0], argboxes[1],
                            argboxes[2])
        if arity == 5:    # copystrcontent, copyunicodecontent
            func = get_execute_function(opnum, 5, False)
            if func:
                return func(cpu, metainterp, argboxes[0], argboxes[1],
                        argboxes[2], argboxes[3], argboxes[4])
    raise NotImplementedError


EXECUTE_BY_NUM_ARGS = _make_execute_list()