vm.c 39.3 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 "nlr.h"
Damien's avatar
Damien committed
6
#include "misc.h"
7
#include "mpconfig.h"
8
#include "qstr.h"
9
#include "obj.h"
Damien's avatar
Damien committed
10
#include "runtime.h"
11
#include "bc0.h"
12
#include "bc.h"
13
#include "objgenerator.h"
Damien's avatar
Damien committed
14

Paul Sokolovsky's avatar
Paul Sokolovsky committed
15
16
17
18
19
20
21
// 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.

22
// Exception stack unwind reasons (WHY_* in CPython-speak)
23
24
// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds
// left to do encoded in the JUMP number
25
26
typedef enum {
    UNWIND_RETURN = 1,
27
    UNWIND_JUMP,
28
29
} mp_unwind_reason_t;

30
31
32
33
34
35
#define DECODE_UINT { \
    unum = 0; \
    do { \
        unum = (unum << 7) + (*ip & 0x7f); \
    } while ((*ip++ & 0x80) != 0); \
}
Damien's avatar
Damien committed
36
37
#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)
38
39
40
41
42
43
#define DECODE_QSTR { \
    qst = 0; \
    do { \
        qst = (qst << 7) + (*ip & 0x7f); \
    } while ((*ip++ & 0x80) != 0); \
}
44
45
#define PUSH(val) *++sp = (val)
#define POP() (*sp--)
46
47
#define TOP() (*sp)
#define SET_TOP(val) *sp = (val)
Damien's avatar
Damien committed
48

49
#define PUSH_EXC_BLOCK() \
50
51
52
53
54
    DECODE_ULABEL; /* except labels are always forward */ \
    ++exc_sp; \
    exc_sp->opcode = op; \
    exc_sp->handler = ip + unum; \
    exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
Damien George's avatar
Damien George committed
55
    exc_sp->prev_exc = MP_OBJ_NULL; \
56
57
    currently_in_except_block = 0; /* in a try block now */

58
59
60
61
#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 */

62
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) {
63
64
65
66
67
68
    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;

69
70
71
72
    // 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;
73

74
75
    // allocate state for locals and stack
    mp_obj_t temp_state[10];
76
    mp_obj_t *state = &temp_state[0];
77
    if (n_state > 10) {
78
        state = m_new(mp_obj_t, n_state);
79
    }
80
81
    mp_obj_t *sp = &state[0] - 1;

82
    // allocate state for exceptions
83
84
    mp_exc_stack_t exc_state[4];
    mp_exc_stack_t *exc_stack = &exc_state[0];
85
    if (n_exc_stack > 4) {
86
        exc_stack = m_new(mp_exc_stack_t, n_exc_stack);
87
    }
88
    mp_exc_stack_t *exc_sp = &exc_stack[0] - 1;
89

90
    // init args
91
    for (uint i = 0; i < n_args; i++) {
92
        state[n_state - 1 - i] = args[i];
93
    }
94
95
96
    for (uint i = 0; i < n_args2; i++) {
        state[n_state - 1 - n_args - i] = args2[i];
    }
97

98
99
100
101
102
103
104
    // bytecode prelude: initialise closed over variables
    for (uint n_local = *ip++; n_local > 0; n_local--) {
        uint local_num = *ip++;
        if (local_num < n_args + n_args2) {
            state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]);
        } else {
            state[n_state - 1 - local_num] = mp_obj_new_cell(MP_OBJ_NULL);
Damien George's avatar
Damien George committed
105
106
107
108
        }
    }

    // execute the byte code
109
    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);
110
111
112
113
114
115
116
117
118
119
120
121
122

    switch (vm_return_kind) {
        case MP_VM_RETURN_NORMAL:
            *ret = *sp;
            return MP_VM_RETURN_NORMAL;
        case MP_VM_RETURN_EXCEPTION:
            *ret = state[n_state - 1];
            return MP_VM_RETURN_EXCEPTION;
        case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
        default:
            assert(0);
            *ret = mp_const_none;
            return MP_VM_RETURN_NORMAL;
123
124
125
    }
}

126
127
// 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
128
129
130
131
// 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]
132
133
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,
134
                                           mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out,
135
                                           volatile mp_obj_t inject_exc) {
Damien's avatar
Damien committed
136
137
    // careful: be sure to declare volatile any variables read in the exception handler (written is ok, I think)

138
    const byte *ip = *ip_in_out;
139
    mp_obj_t *sp = *sp_in_out;
Damien's avatar
Damien committed
140
    machine_uint_t unum;
141
    qstr qst;
142
    mp_obj_t obj1, obj2;
143
    nlr_buf_t nlr;
Damien's avatar
Damien committed
144

145
    volatile bool currently_in_except_block = MP_TAGPTR_TAG(*exc_sp_in_out); // 0 or 1, to detect nested exceptions
146
    mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(*exc_sp_in_out); // stack grows up, exc_sp points to top of stack
147
    const byte *volatile save_ip = ip; // 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)
Damien's avatar
Damien committed
148

149
    // outer exception handling loop
Damien's avatar
Damien committed
150
    for (;;) {
151
outer_dispatch_loop:
152
        if (nlr_push(&nlr) == 0) {
153
154
155
            // 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.
156
157
158
            // 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) {
159
160
                mp_obj_t t = inject_exc;
                inject_exc = MP_OBJ_NULL;
Damien George's avatar
Damien George committed
161
                nlr_jump(mp_make_raise_obj(t));
162
            }
163
164
            // loop to execute byte code
            for (;;) {
165
dispatch_loop:
166
                save_ip = ip;
167
168
                int op = *ip++;
                switch (op) {
169
170
                    case MP_BC_LOAD_CONST_FALSE:
                        PUSH(mp_const_false);
171
172
                        break;

173
174
                    case MP_BC_LOAD_CONST_NONE:
                        PUSH(mp_const_none);
175
176
                        break;

177
178
                    case MP_BC_LOAD_CONST_TRUE:
                        PUSH(mp_const_true);
179
                        break;
Damien George's avatar
Damien George committed
180
181

                    case MP_BC_LOAD_CONST_ELLIPSIS:
182
                        PUSH((mp_obj_t)&mp_const_ellipsis_obj);
Damien George's avatar
Damien George committed
183
                        break;
184

185
                    case MP_BC_LOAD_CONST_SMALL_INT: {
186
                        machine_int_t num = 0;
187
188
189
190
191
192
193
194
                        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));
195
                        break;
196
                    }
197

198
199
                    case MP_BC_LOAD_CONST_INT:
                        DECODE_QSTR;
200
                        PUSH(mp_obj_new_int_from_long_str(qstr_str(qst)));
201
202
                        break;

203
                    case MP_BC_LOAD_CONST_DEC:
Damien's avatar
Damien committed
204
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
205
                        PUSH(mp_load_const_dec(qst));
Damien's avatar
Damien committed
206
207
                        break;

208
                    case MP_BC_LOAD_CONST_ID:
209
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
210
                        PUSH(mp_load_const_str(qst)); // TODO
211
212
                        break;

213
214
                    case MP_BC_LOAD_CONST_BYTES:
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
215
                        PUSH(mp_load_const_bytes(qst));
216
217
                        break;

218
                    case MP_BC_LOAD_CONST_STRING:
219
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
220
                        PUSH(mp_load_const_str(qst));
221
222
                        break;

223
                    case MP_BC_LOAD_FAST_0:
224
                        PUSH(fastn[0]);
225
226
                        break;

227
                    case MP_BC_LOAD_FAST_1:
228
                        PUSH(fastn[-1]);
229
230
                        break;

231
                    case MP_BC_LOAD_FAST_2:
232
                        PUSH(fastn[-2]);
233
234
                        break;

235
                    case MP_BC_LOAD_FAST_N:
236
                        DECODE_UINT;
237
                        PUSH(fastn[-unum]);
238
239
                        break;

240
                    case MP_BC_LOAD_DEREF:
Damien's avatar
Damien committed
241
                        DECODE_UINT;
Damien George's avatar
Damien George committed
242
                        PUSH(mp_get_cell(fastn[-unum]));
Damien's avatar
Damien committed
243
244
                        break;

245
                    case MP_BC_LOAD_NAME:
246
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
247
                        PUSH(mp_load_name(qst));
248
249
                        break;

250
                    case MP_BC_LOAD_GLOBAL:
251
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
252
                        PUSH(mp_load_global(qst));
253
254
                        break;

255
                    case MP_BC_LOAD_ATTR:
256
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
257
                        SET_TOP(mp_load_attr(TOP(), qst));
258
259
                        break;

260
                    case MP_BC_LOAD_METHOD:
261
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
262
                        mp_load_method(*sp, qst, sp);
263
                        sp += 1;
264
265
                        break;

266
                    case MP_BC_LOAD_BUILD_CLASS:
Damien George's avatar
Damien George committed
267
                        PUSH(mp_load_build_class());
268
269
                        break;

270
                    case MP_BC_STORE_FAST_0:
271
                        fastn[0] = POP();
272
273
                        break;

274
                    case MP_BC_STORE_FAST_1:
275
                        fastn[-1] = POP();
276
277
                        break;

278
                    case MP_BC_STORE_FAST_2:
279
                        fastn[-2] = POP();
280
281
                        break;

282
                    case MP_BC_STORE_FAST_N:
283
                        DECODE_UINT;
284
                        fastn[-unum] = POP();
285
286
                        break;

287
                    case MP_BC_STORE_DEREF:
Damien's avatar
Damien committed
288
                        DECODE_UINT;
Damien George's avatar
Damien George committed
289
                        mp_set_cell(fastn[-unum], POP());
Damien's avatar
Damien committed
290
291
                        break;

292
                    case MP_BC_STORE_NAME:
293
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
294
                        mp_store_name(qst, POP());
295
296
                        break;

297
                    case MP_BC_STORE_GLOBAL:
298
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
299
                        mp_store_global(qst, POP());
300
301
                        break;

302
                    case MP_BC_STORE_ATTR:
303
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
304
                        mp_store_attr(sp[0], qst, sp[-1]);
305
                        sp -= 2;
306
307
                        break;

308
                    case MP_BC_STORE_SUBSCR:
Damien George's avatar
Damien George committed
309
                        mp_store_subscr(sp[-1], sp[0], sp[-2]);
310
                        sp -= 3;
311
312
                        break;

313
314
315
316
317
                    case MP_BC_DELETE_FAST_N:
                        DECODE_UINT;
                        fastn[-unum] = MP_OBJ_NULL;
                        break;

318
319
                    case MP_BC_DELETE_NAME:
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
320
                        mp_delete_name(qst);
321
322
                        break;

323
                    case MP_BC_DUP_TOP:
324
                        obj1 = TOP();
325
326
327
                        PUSH(obj1);
                        break;

328
                    case MP_BC_DUP_TOP_TWO:
329
330
331
                        sp += 2;
                        sp[0] = sp[-2];
                        sp[-1] = sp[-3];
332
333
                        break;

334
                    case MP_BC_POP_TOP:
335
                        sp -= 1;
336
337
                        break;

338
                    case MP_BC_ROT_TWO:
339
                        obj1 = sp[0];
340
341
                        sp[0] = sp[-1];
                        sp[-1] = obj1;
342
343
                        break;

344
                    case MP_BC_ROT_THREE:
345
                        obj1 = sp[0];
346
347
348
                        sp[0] = sp[-1];
                        sp[-1] = sp[-2];
                        sp[-2] = obj1;
349
350
                        break;

351
                    case MP_BC_JUMP:
Damien's avatar
Damien committed
352
353
                        DECODE_SLABEL;
                        ip += unum;
354
355
                        break;

356
                    case MP_BC_POP_JUMP_IF_TRUE:
Damien's avatar
Damien committed
357
                        DECODE_SLABEL;
Damien George's avatar
Damien George committed
358
                        if (mp_obj_is_true(POP())) {
Damien's avatar
Damien committed
359
                            ip += unum;
360
361
362
                        }
                        break;

363
                    case MP_BC_POP_JUMP_IF_FALSE:
Damien's avatar
Damien committed
364
                        DECODE_SLABEL;
Damien George's avatar
Damien George committed
365
                        if (!mp_obj_is_true(POP())) {
Damien's avatar
Damien committed
366
                            ip += unum;
367
368
369
                        }
                        break;

370
                    case MP_BC_JUMP_IF_TRUE_OR_POP:
Damien's avatar
Damien committed
371
                        DECODE_SLABEL;
Damien George's avatar
Damien George committed
372
                        if (mp_obj_is_true(TOP())) {
Damien's avatar
Damien committed
373
374
                            ip += unum;
                        } else {
375
                            sp--;
Damien's avatar
Damien committed
376
377
378
                        }
                        break;

379
                    case MP_BC_JUMP_IF_FALSE_OR_POP:
Damien's avatar
Damien committed
380
                        DECODE_SLABEL;
Damien George's avatar
Damien George committed
381
                        if (mp_obj_is_true(TOP())) {
382
                            sp--;
Damien's avatar
Damien committed
383
384
385
386
387
                        } else {
                            ip += unum;
                        }
                        break;

388
                        /* we are trying to get away without using this opcode
389
                    case MP_BC_SETUP_LOOP:
390
                        DECODE_UINT;
391
                        // push_block(MP_BC_SETUP_LOOP, ip + unum, sp)
392
393
394
                        break;
                        */

395
                    case MP_BC_SETUP_WITH:
396
                        obj1 = TOP();
Damien George's avatar
Damien George committed
397
398
399
                        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);
400
                        PUSH_EXC_BLOCK();
401
402
403
404
                        PUSH(obj2);
                        break;

                    case MP_BC_WITH_CLEANUP: {
405
406
407
408
                        // 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.
409
410
411
412
413
                        static const mp_obj_t no_exc[] = {mp_const_none, mp_const_none, mp_const_none};
                        if (TOP() == mp_const_none) {
                            sp--;
                            obj1 = TOP();
                            SET_TOP(mp_const_none);
Damien George's avatar
Damien George committed
414
                            obj2 = mp_call_function_n_kw(obj1, 3, 0, no_exc);
415
416
417
418
419
                        } 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();
Damien George's avatar
Damien George committed
420
                                    obj2 = mp_call_function_n_kw(TOP(), 3, 0, no_exc);
421
422
423
424
425
                                    SET_TOP(retval);
                                    PUSH(cause);
                                    break;
                                }
                                case UNWIND_JUMP: {
Damien George's avatar
Damien George committed
426
                                    obj2 = mp_call_function_n_kw(sp[-2], 3, 0, no_exc);
427
428
429
430
431
432
433
434
435
436
437
                                    // Pop __exit__ boundmethod at sp[-2]
                                    sp[-2] = sp[-1];
                                    sp[-1] = sp[0];
                                    SET_TOP(cause);
                                    break;
                                }
                                default:
                                    assert(0);
                            }
                        } else if (mp_obj_is_exception_type(TOP())) {
                            mp_obj_t args[3] = {sp[0], sp[-1], sp[-2]};
Damien George's avatar
Damien George committed
438
                            obj2 = mp_call_function_n_kw(sp[-3], 3, 0, args);
439
440
441
442
443
444
                            // 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--;
Damien George's avatar
Damien George committed
445
                            if (mp_obj_is_true(obj2)) {
446
447
448
449
                                // 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;
450
451
                                // ... pop "with" exception handler, and signal END_FINALLY
                                // to just execute finally handler normally (by pushing None
452
453
454
                                // on value stack)
                                assert(exc_sp >= exc_stack);
                                assert(exc_sp->opcode == MP_BC_SETUP_WITH);
455
                                POP_EXC_BLOCK();
456
457
458
459
460
461
462
463
                                PUSH(mp_const_none);
                            }
                        } else {
                            assert(0);
                        }
                        break;
                    }

464
465
466
467
468
469
470
471
472
                    case 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;
                            assert(exc_sp >= exc_stack);
473
                            if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
474
475
476
477
478
479
480
481
482
483
484
485
486
                                // 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
                            }
                            exc_sp--;
                        }
                        ip = (const byte*)POP(); // pop destination ip for jump
487
488
                        break;

Damien's avatar
Damien committed
489
                    // matched against: POP_BLOCK or POP_EXCEPT (anything else?)
490
                    case MP_BC_SETUP_EXCEPT:
491
                    case MP_BC_SETUP_FINALLY:
492
                        PUSH_EXC_BLOCK();
493
494
                        break;

495
                    case MP_BC_END_FINALLY:
496
                        // not fully implemented
497
498
                        // if TOS is an exception, reraises the exception (3 values on TOS)
                        // if TOS is None, just pops it and continues
499
                        // if TOS is an integer, does something else
500
                        // else error
501
502
                        if (mp_obj_is_exception_type(TOP())) {
                            nlr_jump(sp[-1]);
503
504
505
                        }
                        if (TOP() == mp_const_none) {
                            sp--;
506
507
508
509
510
511
512
                        } 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;
513
514
                                case UNWIND_JUMP:
                                    goto unwind_jump;
515
516
                            }
                            assert(0);
517
518
519
                        } else {
                            assert(0);
                        }
520
521
                        break;

522
                    case MP_BC_GET_ITER:
Damien George's avatar
Damien George committed
523
                        SET_TOP(mp_getiter(TOP()));
524
525
                        break;

526
                    case MP_BC_FOR_ITER:
Damien's avatar
Damien committed
527
                        DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
Damien George's avatar
Damien George committed
528
                        obj1 = mp_iternext_allow_raise(TOP());
529
                        if (obj1 == MP_OBJ_NULL) {
530
                            --sp; // pop the exhausted iterator
Damien's avatar
Damien committed
531
                            ip += unum; // jump to after for-block
532
533
534
535
536
                        } else {
                            PUSH(obj1); // push the next iteration value
                        }
                        break;

Damien's avatar
Damien committed
537
                    // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
538
                    case MP_BC_POP_BLOCK:
Damien's avatar
Damien committed
539
                        // we are exiting an exception handler, so pop the last one of the exception-stack
540
                        assert(exc_sp >= exc_stack);
541
                        POP_EXC_BLOCK();
542
543
                        break;

544
                    // matched against: SETUP_EXCEPT
545
                    case MP_BC_POP_EXCEPT:
Damien's avatar
Damien committed
546
                        // TODO need to work out how blocks work etc
547
                        // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
548
                        assert(exc_sp >= exc_stack);
549
                        assert(currently_in_except_block);
550
                        //sp = (mp_obj_t*)(*exc_sp--);
Damien's avatar
Damien committed
551
                        //exc_sp--; // discard ip
552
                        POP_EXC_BLOCK();
553
                        //sp -= 3; // pop 3 exception values
554
555
                        break;

556
557
558
559
560
561
562
563
                    case MP_BC_NOT:
                        if (TOP() == mp_const_true) {
                            SET_TOP(mp_const_false);
                        } else {
                            SET_TOP(mp_const_true);
                        }
                        break;

564
                    case MP_BC_UNARY_OP:
Damien's avatar
Damien committed
565
                        unum = *ip++;
Damien George's avatar
Damien George committed
566
                        SET_TOP(mp_unary_op(unum, TOP()));
Damien's avatar
Damien committed
567
568
                        break;

569
                    case MP_BC_BINARY_OP:
570
571
                        unum = *ip++;
                        obj2 = POP();
572
                        obj1 = TOP();
Damien George's avatar
Damien George committed
573
                        SET_TOP(mp_binary_op(unum, obj1, obj2));
574
575
                        break;

576
                    case MP_BC_BUILD_TUPLE:
577
                        DECODE_UINT;
578
                        sp -= unum - 1;
Damien George's avatar
Damien George committed
579
                        SET_TOP(mp_build_tuple(unum, sp));
580
581
                        break;

582
                    case MP_BC_BUILD_LIST:
583
                        DECODE_UINT;
584
                        sp -= unum - 1;
Damien George's avatar
Damien George committed
585
                        SET_TOP(mp_build_list(unum, sp));
586
587
                        break;

588
                    case MP_BC_LIST_APPEND:
589
590
                        DECODE_UINT;
                        // I think it's guaranteed by the compiler that sp[unum] is a list
Damien George's avatar
Damien George committed
591
                        mp_list_append(sp[-unum], sp[0]);
592
                        sp--;
593
594
                        break;

595
                    case MP_BC_BUILD_MAP:
596
                        DECODE_UINT;
Damien George's avatar
Damien George committed
597
                        PUSH(mp_build_map(unum));
598
599
                        break;

600
                    case MP_BC_STORE_MAP:
601
                        sp -= 2;
Damien George's avatar
Damien George committed
602
                        mp_store_map(sp[0], sp[2], sp[1]);
603
604
                        break;

605
                    case MP_BC_MAP_ADD:
Damien's avatar
Damien committed
606
                        DECODE_UINT;
607
                        // I think it's guaranteed by the compiler that sp[-unum - 1] is a map
Damien George's avatar
Damien George committed
608
                        mp_store_map(sp[-unum - 1], sp[0], sp[-1]);
609
                        sp -= 2;
Damien's avatar
Damien committed
610
611
                        break;

612
                    case MP_BC_BUILD_SET:
613
                        DECODE_UINT;
614
                        sp -= unum - 1;
Damien George's avatar
Damien George committed
615
                        SET_TOP(mp_build_set(unum, sp));
616
617
                        break;

618
                    case MP_BC_SET_ADD:
Damien's avatar
Damien committed
619
                        DECODE_UINT;
620
                        // I think it's guaranteed by the compiler that sp[-unum] is a set
Damien George's avatar
Damien George committed
621
                        mp_store_set(sp[-unum], sp[0]);
622
                        sp--;
Damien's avatar
Damien committed
623
624
                        break;

625
#if MICROPY_ENABLE_SLICE
626
627
628
629
630
631
632
633
634
635
636
                    case MP_BC_BUILD_SLICE:
                        DECODE_UINT;
                        if (unum == 2) {
                            obj2 = POP();
                            obj1 = TOP();
                            SET_TOP(mp_obj_new_slice(obj1, obj2, NULL));
                        } else {
                            printf("3-argument slice is not supported\n");
                            assert(0);
                        }
                        break;
637
#endif
638

639
                    case MP_BC_UNPACK_SEQUENCE:
640
                        DECODE_UINT;
Damien George's avatar
Damien George committed
641
                        mp_unpack_sequence(sp[0], unum, sp);
642
                        sp += unum - 1;
643
644
                        break;

645
                    case MP_BC_MAKE_FUNCTION:
646
                        DECODE_UINT;
Damien George's avatar
Damien George committed
647
                        PUSH(mp_make_function_from_id(unum, false, MP_OBJ_NULL));
648
649
650
651
                        break;

                    case MP_BC_MAKE_FUNCTION_DEFARGS:
                        DECODE_UINT;
Damien George's avatar
Damien George committed
652
                        SET_TOP(mp_make_function_from_id(unum, false, TOP()));
653
654
                        break;

655
                    case MP_BC_MAKE_CLOSURE:
Damien's avatar
Damien committed
656
                        DECODE_UINT;
Damien George's avatar
Damien George committed
657
                        SET_TOP(mp_make_closure_from_id(unum, TOP(), MP_OBJ_NULL));
658
659
660
661
662
                        break;

                    case MP_BC_MAKE_CLOSURE_DEFARGS:
                        DECODE_UINT;
                        obj1 = POP();
Damien George's avatar
Damien George committed
663
                        SET_TOP(mp_make_closure_from_id(unum, obj1, TOP()));
Damien's avatar
Damien committed
664
665
                        break;

666
                    case MP_BC_CALL_FUNCTION:
667
                        DECODE_UINT;
668
669
670
                        // unum & 0xff == n_positional
                        // (unum >> 8) & 0xff == n_keyword
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);
Damien George's avatar
Damien George committed
671
                        SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1));
672
673
                        break;

674
                    case MP_BC_CALL_FUNCTION_VAR:
675
676
677
678
                        DECODE_UINT;
                        // unum & 0xff == n_positional
                        // (unum >> 8) & 0xff == n_keyword
                        // We have folowing stack layout here:
679
680
681
682
683
                        // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq <- TOS
                        obj1 = POP();
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);
                        SET_TOP(mp_call_method_n_kw_var(false, unum, sp, obj1, MP_OBJ_NULL));
                        break;
684

685
686
687
688
689
690
691
692
693
694
                    case MP_BC_CALL_FUNCTION_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 ... dict <- TOS
                        obj1 = POP();
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);
                        SET_TOP(mp_call_method_n_kw_var(false, unum, sp, MP_OBJ_NULL, obj1));
                        break;
695

696
697
698
699
700
701
702
703
704
705
                    case 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
                        obj2 = POP();
                        obj1 = POP();
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe);
                        SET_TOP(mp_call_method_n_kw_var(false, unum, sp, obj1, obj2));
706
707
                        break;

708
                    case MP_BC_CALL_METHOD:
709
                        DECODE_UINT;
710
711
712
                        // unum & 0xff == n_positional
                        // (unum >> 8) & 0xff == n_keyword
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1;
Damien George's avatar
Damien George committed
713
                        SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp));
714
                        break;
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748

                    case MP_BC_CALL_METHOD_VAR:
                        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 <- TOS
                        obj1 = POP();
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1;
                        SET_TOP(mp_call_method_n_kw_var(true, unum, sp, obj1, MP_OBJ_NULL));
                        break;

                    case MP_BC_CALL_METHOD_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 ... dict <- TOS
                        obj1 = POP();
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1;
                        SET_TOP(mp_call_method_n_kw_var(true, unum, sp, MP_OBJ_NULL, obj1));
                        break;

                    case 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
                        obj2 = POP();
                        obj1 = POP();
                        sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1;
                        SET_TOP(mp_call_method_n_kw_var(true, unum, sp, obj1, obj2));
                        break;
749

750
                    case MP_BC_RETURN_VALUE:
751
752
unwind_return:
                        while (exc_sp >= exc_stack) {
753
                            if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
754
755
756
757
758
759
760
761
762
763
764
765
766
767
                                // 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 =
                                exc_sp--;
                                goto dispatch_loop;
                            }
                            exc_sp--;
                        }
768
                        nlr_pop();
769
                        *sp_in_out = sp;
770
                        assert(exc_sp == exc_stack - 1);
771
                        return MP_VM_RETURN_NORMAL;
772

773
774
                    case MP_BC_RAISE_VARARGS:
                        unum = *ip++;
775
776
                        assert(unum <= 1);
                        if (unum == 0) {
Damien George's avatar
Damien George committed
777
778
                            // search for the inner-most previous exception, to reraise it
                            obj1 = MP_OBJ_NULL;
779
                            for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) {
Damien George's avatar
Damien George committed
780
781
782
783
784
785
                                if (e->prev_exc != MP_OBJ_NULL) {
                                    obj1 = e->prev_exc;
                                    break;
                                }
                            }
                            if (obj1 == MP_OBJ_NULL) {
786
787
                                nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise"));
                            }
788
789
790
                        } else {
                            obj1 = POP();
                        }
Damien George's avatar
Damien George committed
791
                        nlr_jump(mp_make_raise_obj(obj1));
792

793
                    case MP_BC_YIELD_VALUE:
794
yield:
795
796
797
                        nlr_pop();
                        *ip_in_out = ip;
                        *sp_in_out = sp;
798
                        *exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
799
                        return MP_VM_RETURN_YIELD;
800

801
                    case MP_BC_YIELD_FROM: {
802
803
//#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type)
#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type)
804
#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { nlr_jump(t); }
805
806
                        mp_vm_return_kind_t ret_kind;
                        obj1 = POP();
807
                        mp_obj_t t_exc = MP_OBJ_NULL;
808
                        if (inject_exc != MP_OBJ_NULL) {
809
                            t_exc = inject_exc;
810
                            inject_exc = MP_OBJ_NULL;
811
                            ret_kind = mp_obj_gen_resume(TOP(), mp_const_none, t_exc, &obj2);
812
                        } else {
813
                            ret_kind = mp_obj_gen_resume(TOP(), obj1, MP_OBJ_NULL, &obj2);
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
                        }

                        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 {
                                PUSH(obj2);
                            }

832
833
834
                            // If we injected GeneratorExit downstream, then even
                            // if it was swallowed, we re-raise GeneratorExit
                            GENERATOR_EXIT_IF_NEEDED(t_exc);
835
836
837
838
839
840
                            break;
                        }
                        if (ret_kind == MP_VM_RETURN_EXCEPTION) {
                            // Pop exhausted gen
                            sp--;
                            if (EXC_MATCH(obj2, &mp_type_StopIteration)) {
841
842
843
844
                                PUSH(mp_obj_exception_get_value(obj2));
                                // If we injected GeneratorExit downstream, then even
                                // if it was swallowed, we re-raise GeneratorExit
                                GENERATOR_EXIT_IF_NEEDED(t_exc);
845
846
847
848
849
850
851
                                break;
                            } else {
                                nlr_jump(obj2);
                            }
                        }
                    }

852
                    case MP_BC_IMPORT_NAME:
853
854
                        DECODE_QSTR;
                        obj1 = POP();
Damien George's avatar
Damien George committed
855
                        SET_TOP(mp_import_name(qst, obj1, TOP()));
856
857
                        break;

858
                    case MP_BC_IMPORT_FROM:
859
                        DECODE_QSTR;
Damien George's avatar
Damien George committed
860
                        obj1 = mp_import_from(TOP(), qst);
861
862
863
                        PUSH(obj1);
                        break;

864
                    case MP_BC_IMPORT_STAR:
Damien George's avatar
Damien George committed
865
                        mp_import_all(POP());
866
867
                        break;

868
                    default:
Damien's avatar
Damien committed
869
                        printf("code %p, byte code 0x%02x not implemented\n", ip, op);