Skip to content

Commit 382b3d0

Browse files
committed
Merge pull request adafruit#251 from pfalcon/return_unwind
Add exception stack unwind support for RETURN_VALUE.
2 parents d71cd86 + 6472dea commit 382b3d0

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

py/vm.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ typedef struct _mp_exc_stack {
3030
byte opcode;
3131
} mp_exc_stack;
3232

33+
// Exception stack unwind reasons (WHY_* in CPython-speak)
34+
typedef enum {
35+
UNWIND_RETURN = 1,
36+
UNWIND_BREAK,
37+
UNWIND_CONTINUE,
38+
} mp_unwind_reason_t;
39+
3340
#define DECODE_UINT do { unum = *ip++; if (unum > 127) { unum = ((unum & 0x3f) << 8) | (*ip++); } } while (0)
3441
#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)
3542
#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)
@@ -106,6 +113,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
106113
if (nlr_push(&nlr) == 0) {
107114
// loop to execute byte code
108115
for (;;) {
116+
dispatch_loop:
109117
save_ip = ip;
110118
int op = *ip++;
111119
switch (op) {
@@ -352,6 +360,19 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
352360
}
353361
if (TOP() == mp_const_none) {
354362
sp--;
363+
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
364+
// We finished "finally" coroutine and now dispatch back
365+
// to our caller, based on TOS value
366+
mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP());
367+
switch (reason) {
368+
case UNWIND_RETURN:
369+
goto unwind_return;
370+
// TODO
371+
case UNWIND_BREAK:
372+
case UNWIND_CONTINUE:
373+
;
374+
}
375+
assert(0);
355376
} else {
356377
assert(0);
357378
}
@@ -501,6 +522,23 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
501522
break;
502523

503524
case MP_BC_RETURN_VALUE:
525+
unwind_return:
526+
while (exc_sp >= exc_stack) {
527+
if (exc_sp->opcode == MP_BC_SETUP_FINALLY) {
528+
// We're going to run "finally" code as a coroutine
529+
// (not calling it recursively). Set up a sentinel
530+
// on a stack so it can return back to us when it is
531+
// done (when END_FINALLY reached).
532+
PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN));
533+
ip = exc_sp->handler;
534+
// We don't need to do anything with sp, finally is just
535+
// syntactic sugar for sequential execution??
536+
// sp =
537+
exc_sp--;
538+
goto dispatch_loop;
539+
}
540+
exc_sp--;
541+
}
504542
nlr_pop();
505543
*sp_in_out = sp;
506544
assert(exc_sp == &exc_stack[0] - 1);

tests/basics/try-finally-return.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def func1():
2+
try:
3+
return "it worked"
4+
finally:
5+
print("finally 1")
6+
7+
print(func1())

0 commit comments

Comments
 (0)