vm.c 40.4 KB
Newer Older
Damien's avatar
Damien committed
1
#include <stdio.h>
2
#include <string.h>
Damien's avatar
Damien committed
3
4
#include <assert.h>

5
#include "mpconfig.h"
6
#include "nlr.h"
Damien's avatar
Damien committed
7
#include "misc.h"
8
#include "qstr.h"
9
#include "obj.h"
10
#include "emitglue.h"
Damien's avatar
Damien committed
11
#include "runtime.h"
12
#include "bc0.h"
13
#include "bc.h"
14
#include "objgenerator.h"
Damien's avatar
Damien committed
15

16
17
18
19
20
21
// With these macros you can tune the maximum number of state slots
// that will be allocated on the stack.  Any function that needs more
// than this will use the heap.
#define VM_MAX_STATE_ON_STACK (10)
#define VM_MAX_EXC_STATE_ON_STACK (4)

22
#define DETECT_VM_STACK_OVERFLOW (0)
23
24
25
26
27
#if 0
#define TRACE(ip) mp_byte_code_print2(ip, 1);
#else
#define TRACE(ip)
#endif
28

Paul Sokolovsky's avatar
Paul Sokolovsky committed
29
30
31
32
33
34
35
// Value stack grows up (this makes it incompatible with native C stack, but
// makes sure that arguments to functions are in natural order arg1..argN
// (Python semantics mandates left-to-right evaluation order, including for
// function arguments). Stack pointer is pre-incremented and points at the
// top element.
// Exception stack also grows up, top element is also pointed at.

36
// Exception stack unwind reasons (WHY_* in CPython-speak)
37
38
// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds
// left to do encoded in the JUMP number
39
40
typedef enum {
    UNWIND_RETURN = 1,
41
    UNWIND_JUMP,
42
43
} mp_unwind_reason_t;

44
#define DECODE_UINT do { \
45
46
47
48
    unum = 0; \
    do { \
        unum = (unum << 7) + (*ip & 0x7f); \
    } while ((*ip++ & 0x80) != 0); \
49
} while (0)
Damien's avatar
Damien committed
50
51
#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)
#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)
52
#define DECODE_QSTR do { \
53
54
55
56
    qst = 0; \
    do { \
        qst = (qst << 7) + (*ip & 0x7f); \
    } while ((*ip++ & 0x80) != 0); \
57
58
59
60
61
62
} while (0)
#define DECODE_PTR do { \
    ip = (byte*)(((machine_uint_t)ip + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1))); /* align ip */ \
    unum = *(machine_uint_t*)ip; \
    ip += sizeof(machine_uint_t); \
} while (0)
63
64
#define PUSH(val) *++sp = (val)
#define POP() (*sp--)
65
66
#define TOP() (*sp)
#define SET_TOP(val) *sp = (val)
Damien's avatar
Damien committed
67

68
#define PUSH_EXC_BLOCK() \
69
70
    DECODE_ULABEL; /* except labels are always forward */ \
    ++exc_sp; \
71
    exc_sp->opcode = *save_ip; \
72
73
    exc_sp->handler = ip + unum; \
    exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
Damien George's avatar
Damien George committed
74
    exc_sp->prev_exc = MP_OBJ_NULL; \
75
76
    currently_in_except_block = 0; /* in a try block now */

77
78
79
80
#define POP_EXC_BLOCK() \
    currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \
    exc_sp--; /* pop back to previous exception handler */

81
mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret) {
82
83
84
85
86
87
    const byte *ip = code;

    // get code info size, and skip line number table
    machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
    ip += code_info_size;

88
89
90
91
    // bytecode prelude: state size and exception stack size; 16 bit uints
    machine_uint_t n_state = ip[0] | (ip[1] << 8);
    machine_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
    ip += 4;
92

93
    // allocate state for locals and stack
94
    mp_obj_t temp_state[VM_MAX_STATE_ON_STACK];
95
    mp_obj_t *state = &temp_state[0];
96
#if DETECT_VM_STACK_OVERFLOW
97
98
    n_state += 1;
#endif
99
    if (n_state > VM_MAX_STATE_ON_STACK) {
100
        state = m_new(mp_obj_t, n_state);
101
    }
102
103
    mp_obj_t *sp = &state[0] - 1;

104
    // allocate state for exceptions
105
    mp_exc_stack_t exc_state[VM_MAX_EXC_STATE_ON_STACK];
106
    mp_exc_stack_t *exc_stack = &exc_state[0];
107
    if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
108
        exc_stack = m_new(mp_exc_stack_t, n_exc_stack);
109
    }
110
    mp_exc_stack_t *exc_sp = &exc_stack[0] - 1;
111

112
    // init args
113
    for (uint i = 0; i < n_args; i++) {
114
        state[n_state - 1 - i] = args[i];
115
    }
116
117
118
    for (uint i = 0; i < n_args2; i++) {
        state[n_state - 1 - n_args - i] = args2[i];
    }
119

120
121
122
123
124
    // set rest of state to MP_OBJ_NULL
    for (uint i = 0; i < n_state - n_args - n_args2; i++) {
        state[i] = MP_OBJ_NULL;
    }

125
126
127
    // bytecode prelude: initialise closed over variables
    for (uint n_local = *ip++; n_local > 0; n_local--) {
        uint local_num = *ip++;
128
        state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]);
Damien George's avatar
Damien George committed
129
130
131
    }

    // execute the byte code
132
    mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL);
133

134
#if DETECT_VM_STACK_OVERFLOW
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    // We can't check the case when an exception is returned in state[n_state - 1]
    // and there are no arguments, because in this case our detection slot may have
    // been overwritten by the returned exception (which is allowed).
    if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_args == 0 && n_args2 == 0)) {
        // Just check to see that we have at least 1 null object left in the state.
        bool overflow = true;
        for (uint i = 0; i < n_state - n_args - n_args2; i++) {
            if (state[i] == MP_OBJ_NULL) {
                overflow = false;
                break;
            }
        }
        if (overflow) {
            printf("VM stack overflow state=%p n_state+1=%u\n", state, n_state);
            assert(0);
        }
151
152
153
    }
#endif

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    mp_vm_return_kind_t ret_kind;
    switch (vm_return_kind) {
        case MP_VM_RETURN_NORMAL:
            // return value is in *sp
            *ret = *sp;
            ret_kind = MP_VM_RETURN_NORMAL;
            break;

        case MP_VM_RETURN_EXCEPTION:
            // return value is in state[n_state - 1]
            *ret = state[n_state - 1];
            ret_kind = MP_VM_RETURN_EXCEPTION;
            break;

        case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
        default:
            assert(0);
            *ret = mp_const_none;
            ret_kind = MP_VM_RETURN_NORMAL;
    }
174
175
176
177
178

    // free the state if it was allocated on the heap
    if (n_state > VM_MAX_STATE_ON_STACK) {
        m_free(state, n_state);
    }
179
180

    // free the exception state if it was allocated on the heap
181
182
183
184
    if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
        m_free(exc_stack, n_exc_stack);
    }

185
    return ret_kind;
186
187
}

188
189
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
// sp points to bottom of stack which grows up
190
191
192
193
// returns:
//  MP_VM_RETURN_NORMAL, sp valid, return value in *sp
//  MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
//  MP_VM_RETURN_EXCEPTION, exception in fastn[0]
194
195
mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out,
                                           mp_obj_t *fastn, mp_obj_t **sp_in_out,
196
                                           mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out,
197
                                           volatile mp_obj_t inject_exc) {
198
#if MICROPY_USE_COMPUTED_GOTO
AZ Huang's avatar
AZ Huang committed
199
    #include "vmentrytable.h"
200
    #define DISPATCH() do { \
201
        TRACE(ip); \
202
        save_ip = ip; \
203
        goto *entry_table[*ip++]; \
204
    } while(0)
205
206
    #define ENTRY(op) entry_##op
    #define ENTRY_DEFAULT entry_default
207
#else
208
209
210
    #define DISPATCH() break
    #define ENTRY(op) case op
    #define ENTRY_DEFAULT default
211
212
#endif

213
214
215
216
217
    // nlr_raise needs to be implemented as a goto, so that the C compiler's flow analyser
    // sees that it's possible for us to jump from the dispatch loop to the exception
    // handler.  Without this, the code may have a different stack layout in the dispatch
    // loop and the exception handler, leading to very obscure bugs.
    #define RAISE(o) do { nlr_pop(); nlr.ret_val = o; goto exception_handler; } while(0)
Damien's avatar
Damien committed
218

219
    // variables that are visible to the exception handler (declared volatile)
220
    volatile bool currently_in_except_block = MP_TAGPTR_TAG(*exc_sp_in_out); // 0 or 1, to detect nested exceptions
221
    mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(*exc_sp_in_out); // stack grows up, exc_sp points to top of stack
222
223
    const byte *volatile save_ip = *ip_in_out; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
    mp_obj_t *volatile save_sp = *sp_in_out; // this is so we can access sp in the exception handler when needed
Damien's avatar
Damien committed
224

225
    // outer exception handling loop
Damien's avatar
Damien committed
226
    for (;;) {
227
        nlr_buf_t nlr;
228
outer_dispatch_loop:
229
        if (nlr_push(&nlr) == 0) {
230
231
232
233
234
235
236
            // local variables that are not visible to the exception handler
            const byte *ip = *ip_in_out;
            mp_obj_t *sp = *sp_in_out;
            machine_uint_t unum;
            qstr qst;
            mp_obj_t obj1, obj2;

237
238
239
            // If we have exception to inject, now that we finish setting up
            // execution context, raise it. This works as if RAISE_VARARGS
            // bytecode was executed.
240
241
242
            // Injecting exc into yield from generator is a special case,
            // handled by MP_BC_YIELD_FROM itself
            if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) {
243
                obj1 = inject_exc;
244
                inject_exc = MP_OBJ_NULL;
245
246
                obj1 = mp_make_raise_obj(obj1);
                RAISE(obj1);
247
            }
248

249
250
            // loop to execute byte code
            for (;;) {
251
dispatch_loop:
252
#if MICROPY_USE_COMPUTED_GOTO
253
254
                DISPATCH();
#else
255
                TRACE(ip);
256
                save_ip = ip;
257
                switch (*ip++) {
258
#endif
259

260
261
262
                ENTRY(MP_BC_LOAD_CONST_FALSE):
                    PUSH(mp_const_false);
                    DISPATCH();
263

264
265
266
                ENTRY(MP_BC_LOAD_CONST_NONE):
                    PUSH(mp_const_none);
                    DISPATCH();
267

268
269
270
                ENTRY(MP_BC_LOAD_CONST_TRUE):
                    PUSH(mp_const_true);
                    DISPATCH();
271

272
273
274
                ENTRY(MP_BC_LOAD_CONST_ELLIPSIS):
                    PUSH((mp_obj_t)&mp_const_ellipsis_obj);
                    DISPATCH();
275

276
277
278
279
280
281
282
283
284
285
286
287
                ENTRY(MP_BC_LOAD_CONST_SMALL_INT): {
                    machine_int_t num = 0;
                    if ((ip[0] & 0x40) != 0) {
                        // Number is negative
                        num--;
                    }
                    do {
                        num = (num << 7) | (*ip & 0x7f);
                    } while ((*ip++ & 0x80) != 0);
                    PUSH(MP_OBJ_NEW_SMALL_INT(num));
                    DISPATCH();
                }
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
                ENTRY(MP_BC_LOAD_CONST_INT):
                    DECODE_QSTR;
                    PUSH(mp_obj_new_int_from_long_str(qstr_str(qst)));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_CONST_DEC):
                    DECODE_QSTR;
                    PUSH(mp_load_const_dec(qst));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_CONST_BYTES):
                    DECODE_QSTR;
                    PUSH(mp_load_const_bytes(qst));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_CONST_STRING):
                    DECODE_QSTR;
                    PUSH(mp_load_const_str(qst));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_NULL):
                    PUSH(MP_OBJ_NULL);
                    DISPATCH();

                ENTRY(MP_BC_LOAD_FAST_0):
                    obj1 = fastn[0];
                    goto load_check;

                ENTRY(MP_BC_LOAD_FAST_1):
                    obj1 = fastn[-1];
                    goto load_check;

                ENTRY(MP_BC_LOAD_FAST_2):
                    obj1 = fastn[-2];
                    goto load_check;

                ENTRY(MP_BC_LOAD_FAST_N):
                    DECODE_UINT;
                    obj1 = fastn[-unum];
                    load_check:
                    if (obj1 == MP_OBJ_NULL) {
                        local_name_error:
331
332
                        obj1 = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment");
                        RAISE(obj1);
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
                    }
                    PUSH(obj1);
                    DISPATCH();

                ENTRY(MP_BC_LOAD_DEREF):
                    DECODE_UINT;
                    obj1 = mp_obj_cell_get(fastn[-unum]);
                    goto load_check;

                ENTRY(MP_BC_LOAD_NAME):
                    DECODE_QSTR;
                    PUSH(mp_load_name(qst));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_GLOBAL):
                    DECODE_QSTR;
                    PUSH(mp_load_global(qst));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_ATTR):
                    DECODE_QSTR;
                    SET_TOP(mp_load_attr(TOP(), qst));
                    DISPATCH();

                ENTRY(MP_BC_LOAD_METHOD):
                    DECODE_QSTR;
                    mp_load_method(*sp, qst, sp);
                    sp += 1;
                    DISPATCH();

                ENTRY(MP_BC_LOAD_BUILD_CLASS):
                    PUSH(mp_load_build_class());
                    DISPATCH();

367
368
369
370
371
                ENTRY(MP_BC_LOAD_SUBSCR):
                    obj1 = POP();
                    SET_TOP(mp_obj_subscr(TOP(), obj1, MP_OBJ_SENTINEL));
                    DISPATCH();

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
                ENTRY(MP_BC_STORE_FAST_0):
                    fastn[0] = POP();
                    DISPATCH();

                ENTRY(MP_BC_STORE_FAST_1):
                    fastn[-1] = POP();
                    DISPATCH();

                ENTRY(MP_BC_STORE_FAST_2):
                    fastn[-2] = POP();
                    DISPATCH();

                ENTRY(MP_BC_STORE_FAST_N):
                    DECODE_UINT;
                    fastn[-unum] = POP();
                    DISPATCH();

                ENTRY(MP_BC_STORE_DEREF):
                    DECODE_UINT;
                    mp_obj_cell_set(fastn[-unum], POP());
                    DISPATCH();

                ENTRY(MP_BC_STORE_NAME):
                    DECODE_QSTR;
                    mp_store_name(qst, POP());
                    DISPATCH();

                ENTRY(MP_BC_STORE_GLOBAL):
                    DECODE_QSTR;
                    mp_store_global(qst, POP());
                    DISPATCH();

                ENTRY(MP_BC_STORE_ATTR):
                    DECODE_QSTR;
                    mp_store_attr(sp[0], qst, sp[-1]);
                    sp -= 2;
                    DISPATCH();

                ENTRY(MP_BC_STORE_SUBSCR):
411
                    mp_obj_subscr(sp[-1], sp[0], sp[-2]);
412
413
414
415
416
417
418
419
420
421
                    sp -= 3;
                    DISPATCH();

                ENTRY(MP_BC_DELETE_FAST):
                    DECODE_UINT;
                    if (fastn[-unum] == MP_OBJ_NULL) {
                        goto local_name_error;
                    }
                    fastn[-unum] = MP_OBJ_NULL;
                    DISPATCH();
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
                ENTRY(MP_BC_DELETE_DEREF):
                    DECODE_UINT;
                    if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) {
                        goto local_name_error;
                    }
                    mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL);
                    DISPATCH();

                ENTRY(MP_BC_DELETE_NAME):
                    DECODE_QSTR;
                    mp_delete_name(qst);
                    DISPATCH();

                ENTRY(MP_BC_DELETE_GLOBAL):
                    DECODE_QSTR;
                    mp_delete_global(qst);
                    DISPATCH();

                ENTRY(MP_BC_DUP_TOP):
                    obj1 = TOP();
                    PUSH(obj1);
                    DISPATCH();

                ENTRY(MP_BC_DUP_TOP_TWO):
                    sp += 2;
                    sp[0] = sp[-2];
                    sp[-1] = sp[-3];
                    DISPATCH();

                ENTRY(MP_BC_POP_TOP):
                    sp -= 1;
                    DISPATCH();

                ENTRY(MP_BC_ROT_TWO):
                    obj1 = sp[0];
                    sp[0] = sp[-1];
                    sp[-1] = obj1;
                    DISPATCH();

                ENTRY(MP_BC_ROT_THREE):
                    obj1 = sp[0];
                    sp[0] = sp[-1];
                    sp[-1] = sp[-2];
                    sp[-2] = obj1;
                    DISPATCH();

                ENTRY(MP_BC_JUMP):
                    DECODE_SLABEL;
                    ip += unum;
                    DISPATCH();

                ENTRY(MP_BC_POP_JUMP_IF_TRUE):
                    DECODE_SLABEL;
                    if (mp_obj_is_true(POP())) {
                        ip += unum;
                    }
                    DISPATCH();
Damien's avatar
Damien committed
480

481
482
483
484
485
486
                ENTRY(MP_BC_POP_JUMP_IF_FALSE):
                    DECODE_SLABEL;
                    if (!mp_obj_is_true(POP())) {
                        ip += unum;
                    }
                    DISPATCH();
Damien's avatar
Damien committed
487

488
489
490
491
492
493
494
495
                ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP):
                    DECODE_SLABEL;
                    if (mp_obj_is_true(TOP())) {
                        ip += unum;
                    } else {
                        sp--;
                    }
                    DISPATCH();
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
                ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP):
                    DECODE_SLABEL;
                    if (mp_obj_is_true(TOP())) {
                        sp--;
                    } else {
                        ip += unum;
                    }
                    DISPATCH();

                ENTRY(MP_BC_SETUP_WITH):
                    obj1 = TOP();
                    SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__));
                    mp_load_method(obj1, MP_QSTR___enter__, sp + 1);
                    obj2 = mp_call_method_n_kw(0, 0, sp + 1);
                    PUSH_EXC_BLOCK();
                    PUSH(obj2);
                    DISPATCH();

                ENTRY(MP_BC_WITH_CLEANUP): {
                    // Arriving here, there's "exception control block" on top of stack,
                    // and __exit__ bound method underneath it. Bytecode calls __exit__,
                    // and "deletes" it off stack, shifting "exception control block"
                    // to its place.
                    static const mp_obj_t no_exc[] = {mp_const_none, mp_const_none, mp_const_none};
                    if (TOP() == mp_const_none) {
                        sp--;
523
                        obj1 = TOP();
524
525
526
527
528
529
530
531
532
533
534
                        SET_TOP(mp_const_none);
                        obj2 = mp_call_function_n_kw(obj1, 3, 0, no_exc);
                    } else if (MP_OBJ_IS_SMALL_INT(TOP())) {
                        mp_obj_t cause = POP();
                        switch (MP_OBJ_SMALL_INT_VALUE(cause)) {
                            case UNWIND_RETURN: {
                                mp_obj_t retval = POP();
                                obj2 = mp_call_function_n_kw(TOP(), 3, 0, no_exc);
                                SET_TOP(retval);
                                PUSH(cause);
                                break;
535
                            }
536
537
538
539
540
541
542
                            case UNWIND_JUMP: {
                                obj2 = mp_call_function_n_kw(sp[-2], 3, 0, no_exc);
                                // Pop __exit__ boundmethod at sp[-2]
                                sp[-2] = sp[-1];
                                sp[-1] = sp[0];
                                SET_TOP(cause);
                                break;
543
                            }
544
545
                            default:
                                assert(0);
546
                        }
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
                    } else if (mp_obj_is_exception_type(TOP())) {
                        mp_obj_t args[3] = {sp[0], sp[-1], sp[-2]};
                        obj2 = mp_call_function_n_kw(sp[-3], 3, 0, args);
                        // Pop __exit__ boundmethod at sp[-3]
                        // TODO: Once semantics is proven, optimize for case when obj2 == True
                        sp[-3] = sp[-2];
                        sp[-2] = sp[-1];
                        sp[-1] = sp[0];
                        sp--;
                        if (mp_obj_is_true(obj2)) {
                            // This is what CPython does
                            //PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED));
                            // But what we need to do is - pop exception from value stack...
                            sp -= 3;
                            // ... pop "with" exception handler, and signal END_FINALLY
                            // to just execute finally handler normally (by pushing None
                            // on value stack)
564
                            assert(exc_sp >= exc_stack);
565
566
567
                            assert(exc_sp->opcode == MP_BC_SETUP_WITH);
                            POP_EXC_BLOCK();
                            PUSH(mp_const_none);
568
                        }
569
570
571
572
573
                    } else {
                        assert(0);
                    }
                    DISPATCH();
                }
574

575
576
577
578
579
580
581
582
                ENTRY(MP_BC_UNWIND_JUMP):
                    DECODE_SLABEL;
                    PUSH((void*)(ip + unum)); // push destination ip for jump
                    PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind
unwind_jump:
                    unum = (machine_uint_t)POP(); // get number of exception handlers to unwind
                    while (unum > 0) {
                        unum -= 1;
583
                        assert(exc_sp >= exc_stack);
584
585
586
587
588
589
590
591
592
593
                        if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
                            // We're going to run "finally" code as a coroutine
                            // (not calling it recursively). Set up a sentinel
                            // on a stack so it can return back to us when it is
                            // done (when END_FINALLY reached).
                            PUSH((void*)unum); // push number of exception handlers left to unwind
                            PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel
                            ip = exc_sp->handler; // get exception handler byte code address
                            exc_sp--; // pop exception handler
                            goto dispatch_loop; // run the exception handler
594
                        }
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
                        exc_sp--;
                    }
                    ip = (const byte*)POP(); // pop destination ip for jump
                    DISPATCH();

                // matched against: POP_BLOCK or POP_EXCEPT (anything else?)
                ENTRY(MP_BC_SETUP_EXCEPT):
                ENTRY(MP_BC_SETUP_FINALLY):
                    PUSH_EXC_BLOCK();
                    DISPATCH();

                ENTRY(MP_BC_END_FINALLY):
                    // not fully implemented
                    // if TOS is an exception, reraises the exception (3 values on TOS)
                    // if TOS is None, just pops it and continues
                    // if TOS is an integer, does something else
                    // else error
                    if (mp_obj_is_exception_type(TOP())) {
613
                        RAISE(sp[-1]);
614
615
                    }
                    if (TOP() == mp_const_none) {
616
                        sp--;
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
                    } else if (MP_OBJ_IS_SMALL_INT(TOP())) {
                        // We finished "finally" coroutine and now dispatch back
                        // to our caller, based on TOS value
                        mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP());
                        switch (reason) {
                            case UNWIND_RETURN:
                                goto unwind_return;
                            case UNWIND_JUMP:
                                goto unwind_jump;
                        }
                        assert(0);
                    } else {
                        assert(0);
                    }
                    DISPATCH();

                ENTRY(MP_BC_GET_ITER):
                    SET_TOP(mp_getiter(TOP()));
                    DISPATCH();

                ENTRY(MP_BC_FOR_ITER):
                    DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
639
                    save_sp = sp;
640
                    obj1 = mp_iternext_allow_raise(TOP());
641
                    if (obj1 == MP_OBJ_STOP_ITERATION) {
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
                        --sp; // pop the exhausted iterator
                        ip += unum; // jump to after for-block
                    } else {
                        PUSH(obj1); // push the next iteration value
                    }
                    DISPATCH();

                // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
                ENTRY(MP_BC_POP_BLOCK):
                    // we are exiting an exception handler, so pop the last one of the exception-stack
                    assert(exc_sp >= exc_stack);
                    POP_EXC_BLOCK();
                    DISPATCH();

                // matched against: SETUP_EXCEPT
                ENTRY(MP_BC_POP_EXCEPT):
                    // TODO need to work out how blocks work etc
                    // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
                    assert(exc_sp >= exc_stack);
                    assert(currently_in_except_block);
                    //sp = (mp_obj_t*)(*exc_sp--);
                    //exc_sp--; // discard ip
                    POP_EXC_BLOCK();
                    //sp -= 3; // pop 3 exception values
                    DISPATCH();

                ENTRY(MP_BC_NOT):
                    if (TOP() == mp_const_true) {
                        SET_TOP(mp_const_false);
                    } else {
                        SET_TOP(mp_const_true);
                    }
                    DISPATCH();

                ENTRY(MP_BC_UNARY_OP):
                    unum = *ip++;
                    SET_TOP(mp_unary_op(unum, TOP()));
                    DISPATCH();

                ENTRY(MP_BC_BINARY_OP):
                    unum = *ip++;
                    obj2 = POP();
                    obj1 = TOP();
                    SET_TOP(mp_binary_op(unum, obj1, obj2));
                    DISPATCH();

                ENTRY(MP_BC_BUILD_TUPLE):
                    DECODE_UINT;
                    sp -= unum - 1;
                    SET_TOP(mp_obj_new_tuple(unum, sp));
                    DISPATCH();

                ENTRY(MP_BC_BUILD_LIST):
                    DECODE_UINT;
                    sp -= unum - 1;
                    SET_TOP(mp_obj_new_list(unum, sp));
                    DISPATCH();

                ENTRY(MP_BC_LIST_APPEND):
                    DECODE_UINT;
                    // I think it's guaranteed by the compiler that sp[unum] is a list
                    mp_obj_list_append(sp[-unum], sp[0]);
                    sp--;
                    DISPATCH();

                ENTRY(MP_BC_BUILD_MAP):
                    DECODE_UINT;
                    PUSH(mp_obj_new_dict(unum));
                    DISPATCH();

                ENTRY(MP_BC_STORE_MAP):
                    sp -= 2;
                    mp_obj_dict_store(sp[0], sp[2], sp[1]);
                    DISPATCH();

                ENTRY(MP_BC_MAP_ADD):
                    DECODE_UINT;
                    // I think it's guaranteed by the compiler that sp[-unum - 1] is a map
                    mp_obj_dict_store(sp[-unum - 1], sp[0], sp[-1]);
                    sp -= 2;
                    DISPATCH();

                ENTRY(MP_BC_BUILD_SET):
                    DECODE_UINT;
                    sp -= unum - 1;
                    SET_TOP(mp_obj_new_set(unum, sp));
                    DISPATCH();

                ENTRY(MP_BC_SET_ADD):
                    DECODE_UINT;
                    // I think it's guaranteed by the compiler that sp[-unum] is a set
                    mp_obj_set_store(sp[-unum], sp[0]);
                    sp--;
                    DISPATCH();
Damien's avatar
Damien committed
736

737
#if MICROPY_ENABLE_SLICE
738
739
740
741
742
743
744
745
746
747
748
749
750
                ENTRY(MP_BC_BUILD_SLICE):
                    DECODE_UINT;
                    if (unum == 2) {
                        obj2 = POP();
                        obj1 = TOP();
                        SET_TOP(mp_obj_new_slice(obj1, obj2, NULL));
                    } else {
                        obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported");
                        nlr_pop();
                        fastn[0] = obj1;
                        return MP_VM_RETURN_EXCEPTION;
                    }
                    DISPATCH();
751
#endif
752

753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
                ENTRY(MP_BC_UNPACK_SEQUENCE):
                    DECODE_UINT;
                    mp_unpack_sequence(sp[0], unum, sp);
                    sp += unum - 1;
                    DISPATCH();

                ENTRY(MP_BC_UNPACK_EX):
                    DECODE_UINT;
                    mp_unpack_ex(sp[0], unum, sp);
                    sp += (unum & 0xff) + ((unum >> 8) & 0xff);
                    DISPATCH();

                ENTRY(MP_BC_MAKE_FUNCTION):
                    DECODE_PTR;
                    PUSH(mp_make_function_from_raw_code((mp_raw_code_t*)unum, MP_OBJ_NULL, MP_OBJ_NULL));
                    DISPATCH();

                ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS):
                    DECODE_PTR;
                    // Stack layout: def_tuple def_dict <- TOS
                    obj1 = POP();
                    SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1));
                    DISPATCH();

777
                ENTRY(MP_BC_MAKE_CLOSURE): {
778
                    DECODE_PTR;
779
780
781
782
                    machine_uint_t n_closed_over = *ip++;
                    // Stack layout: closed_overs <- TOS
                    sp -= n_closed_over - 1;
                    SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, n_closed_over, sp));
783
                    DISPATCH();
784
                }
785

786
                ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): {
787
                    DECODE_PTR;
788
789
790
791
                    machine_uint_t n_closed_over = *ip++;
                    // Stack layout: def_tuple def_dict closed_overs <- TOS
                    sp -= 2 + n_closed_over - 1;
                    SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, 0x100 | n_closed_over, sp));
792
                    DISPATCH();
793
                }
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831

                ENTRY(MP_BC_CALL_FUNCTION):
                    DECODE_UINT;
                    // unum & 0xff == n_positional
                    // (unum >> 8) & 0xff == n_keyword
                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);
                    SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1));
                    DISPATCH();

                ENTRY(MP_BC_CALL_FUNCTION_VAR_KW):
                    DECODE_UINT;
                    // unum & 0xff == n_positional
                    // (unum >> 8) & 0xff == n_keyword
                    // We have folowing stack layout here:
                    // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS
                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2;
                    SET_TOP(mp_call_method_n_kw_var(false, unum, sp));
                    DISPATCH();

                ENTRY(MP_BC_CALL_METHOD):
                    DECODE_UINT;
                    // unum & 0xff == n_positional
                    // (unum >> 8) & 0xff == n_keyword
                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1;
                    SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp));
                    DISPATCH();

                ENTRY(MP_BC_CALL_METHOD_VAR_KW):
                    DECODE_UINT;
                    // unum & 0xff == n_positional
                    // (unum >> 8) & 0xff == n_keyword
                    // We have folowing stack layout here:
                    // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS
                    sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3;
                    SET_TOP(mp_call_method_n_kw_var(true, unum, sp));
                    DISPATCH();

                ENTRY(MP_BC_RETURN_VALUE):
832
unwind_return:
833
834
835
836
837
838
839
840
841
842
843
                    while (exc_sp >= exc_stack) {
                        if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
                            // We're going to run "finally" code as a coroutine
                            // (not calling it recursively). Set up a sentinel
                            // on a stack so it can return back to us when it is
                            // done (when END_FINALLY reached).
                            PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN));
                            ip = exc_sp->handler;
                            // We don't need to do anything with sp, finally is just
                            // syntactic sugar for sequential execution??
                            // sp =
844
                            exc_sp--;
845
                            goto dispatch_loop;
846
                        }
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
                        exc_sp--;
                    }
                    nlr_pop();
                    *sp_in_out = sp;
                    assert(exc_sp == exc_stack - 1);
                    return MP_VM_RETURN_NORMAL;

                ENTRY(MP_BC_RAISE_VARARGS):
                    unum = *ip++;
                    assert(unum <= 1);
                    if (unum == 0) {
                        // search for the inner-most previous exception, to reraise it
                        obj1 = MP_OBJ_NULL;
                        for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) {
                            if (e->prev_exc != MP_OBJ_NULL) {
                                obj1 = e->prev_exc;
                                break;
864
                            }
865
                        }
866
                        if (obj1 == MP_OBJ_NULL) {
867
868
                            obj1 = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise");
                            RAISE(obj1);
869
870
871
872
                        }
                    } else {
                        obj1 = POP();
                    }
873
874
                    obj1 = mp_make_raise_obj(obj1);
                    RAISE(obj1);
875

876
                ENTRY(MP_BC_YIELD_VALUE):
877
yield:
878
879
880
881
882
                    nlr_pop();
                    *ip_in_out = ip;
                    *sp_in_out = sp;
                    *exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
                    return MP_VM_RETURN_YIELD;
883

884
                ENTRY(MP_BC_YIELD_FROM): {
885
886
//#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type)
#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type)
887
#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { RAISE(t); }
888
889
890
891
892
893
894
895
896
897
                    mp_vm_return_kind_t ret_kind;
                    obj1 = POP();
                    mp_obj_t t_exc = MP_OBJ_NULL;
                    if (inject_exc != MP_OBJ_NULL) {
                        t_exc = inject_exc;
                        inject_exc = MP_OBJ_NULL;
                        ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &obj2);
                    } else {
                        ret_kind = mp_resume(TOP(), obj1, MP_OBJ_NULL, &obj2);
                    }
898

899
900
901
902
903
904
905
906
907
908
909
910
911
                    if (ret_kind == MP_VM_RETURN_YIELD) {
                        ip--;
                        PUSH(obj2);
                        goto yield;
                    }
                    if (ret_kind == MP_VM_RETURN_NORMAL) {
                        // Pop exhausted gen
                        sp--;
                        if (obj2 == MP_OBJ_NULL) {
                            // Optimize StopIteration
                            // TODO: get StopIteration's value
                            PUSH(mp_const_none);
                        } else {
912
913
914
                            PUSH(obj2);
                        }

915
916
917
918
919
920
921
922
923
924
                        // If we injected GeneratorExit downstream, then even
                        // if it was swallowed, we re-raise GeneratorExit
                        GENERATOR_EXIT_IF_NEEDED(t_exc);
                        DISPATCH();
                    }
                    if (ret_kind == MP_VM_RETURN_EXCEPTION) {
                        // Pop exhausted gen
                        sp--;
                        if (EXC_MATCH(obj2, &mp_type_StopIteration)) {
                            PUSH(mp_obj_exception_get_value(obj2));
925
926
927
                            // If we injected GeneratorExit downstream, then even
                            // if it was swallowed, we re-raise GeneratorExit
                            GENERATOR_EXIT_IF_NEEDED(t_exc);
928
929
                            DISPATCH();
                        } else {
930
                            RAISE(obj2);
931
932
                        }
                    }
933
                }
934

935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
                ENTRY(MP_BC_IMPORT_NAME):
                    DECODE_QSTR;
                    obj1 = POP();
                    SET_TOP(mp_import_name(qst, obj1, TOP()));
                    DISPATCH();

                ENTRY(MP_BC_IMPORT_FROM):
                    DECODE_QSTR;
                    obj1 = mp_import_from(TOP(), qst);
                    PUSH(obj1);
                    DISPATCH();

                ENTRY(MP_BC_IMPORT_STAR):
                    mp_import_all(POP());
                    DISPATCH();

                ENTRY_DEFAULT:
                    obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
                    nlr_pop();
                    fastn[0] = obj1;
                    return MP_VM_RETURN_EXCEPTION;
956

957
#if !MICROPY_USE_COMPUTED_GOTO
958
                } // switch
959
#endif
960
            } // for loop
961
962

        } else {
963
exception_handler:
964
965
            // exception occurred

966
967
            // check if it's a StopIteration within a for block
            if (*save_ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
968
969
                const byte *ip = save_ip + 1;
                machine_uint_t unum;
970
                DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
971
972
                *ip_in_out = ip + unum; // jump to after for-block
                *sp_in_out = save_sp - 1; // pop the exhausted iterator
973
974
975
                goto outer_dispatch_loop; // continue with dispatch loop
            }

976
            // set file and line number that the exception occurred at
977
978
            // TODO: don't set traceback for exceptions re-raised by END_FINALLY.
            // But consider how to handle nested exceptions.
979
980
            // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj)
            if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) {
981
                machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24);
982
983
                qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
                qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
984
985
                machine_uint_t source_line = 1;
                machine_uint_t bc = save_ip - code_info - code_info_size;
986
                //printf("find %lu %d %d\n", bc, code_info[12], code_info[13]);
987
988
989
                for (const byte* ci = code_info + 12; *ci && bc >= ((*ci) & 31); ci++) {
                    bc -= *ci & 31;
                    source_line += *ci >> 5;
990
                }
991
                mp_obj_exception_add_traceback(nlr.ret_val, source_file, source_line, block_name);
992
993
            }

994
995
996
            while (currently_in_except_block) {
                // nested exception

997
                assert(exc_sp >= exc_stack);
998
999
1000

                // TODO make a proper message for nested exception
                // at the moment we are just raising the very last exception (the one that caused the nested exception)
For faster browsing, not all history is shown. View entire blame