Skip to content

Commit ce89a21

Browse files
committed
Implement basic exception framework, and simple for loop.
1 parent 5dd455d commit ce89a21

9 files changed

Lines changed: 589 additions & 243 deletions

File tree

py/compile.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
// TODO need to mangle __attr names
1818

19+
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
20+
1921
typedef enum {
2022
PN_none = 0,
2123
#define DEF_RULE(rule, comp, kind, arg...) PN_##rule,
@@ -853,16 +855,19 @@ static bool compile_built_in_decorator(compiler_t *comp, int name_len, py_parse_
853855
}
854856

855857
qstr attr = PY_PARSE_NODE_LEAF_ARG(name_nodes[1]);
856-
if (attr == comp->qstr_native) {
858+
if (0) {
859+
#if MICROPY_EMIT_NATIVE
860+
} else if (attr == comp->qstr_native) {
857861
*emit_options = EMIT_OPT_NATIVE_PYTHON;
858862
} else if (attr == comp->qstr_viper) {
859863
*emit_options = EMIT_OPT_VIPER;
864+
#endif
860865
#if MICROPY_EMIT_INLINE_THUMB
861866
} else if (attr == comp->qstr_asm_thumb) {
862867
*emit_options = EMIT_OPT_ASM_THUMB;
863868
#endif
864869
} else {
865-
printf("SyntaxError: invalid micropython decorator\n");
870+
printf("SyntaxError: invalid micropython decorator '%s'\n", qstr_str(attr));
866871
}
867872

868873
return true;
@@ -1302,37 +1307,44 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
13021307
int old_break_label = comp->break_label;
13031308
int old_continue_label = comp->continue_label;
13041309

1305-
int done_label = comp_next_label(comp);
1306-
int end_label = comp_next_label(comp);
13071310
int break_label = comp_next_label(comp);
13081311
int continue_label = comp_next_label(comp);
13091312

13101313
comp->break_label = break_label;
13111314
comp->continue_label = continue_label;
13121315

1313-
EMIT(setup_loop, end_label);
1316+
// compared to CPython, we have an optimised version of while loops
1317+
#if MICROPY_EMIT_CPYTHON
1318+
int done_label = comp_next_label(comp);
1319+
EMIT(setup_loop, break_label);
13141320
EMIT(label_assign, continue_label);
13151321
c_if_cond(comp, pns->nodes[0], false, done_label); // condition
13161322
compile_node(comp, pns->nodes[1]); // body
13171323
if (!EMIT(last_emit_was_return_value)) {
13181324
EMIT(jump, continue_label);
13191325
}
13201326
EMIT(label_assign, done_label);
1321-
1322-
// break/continue apply to outer loop (if any) in the else block
1323-
comp->break_label = old_break_label;
1324-
comp->continue_label = old_continue_label;
1325-
13261327
// CPython does not emit POP_BLOCK if the condition was a constant; don't undertand why
13271328
// this is a small hack to agree with CPython
13281329
if (!node_is_const_true(pns->nodes[0])) {
13291330
EMIT(pop_block);
13301331
}
1332+
#else
1333+
int top_label = comp_next_label(comp);
1334+
EMIT(jump, continue_label);
1335+
EMIT(label_assign, top_label);
1336+
compile_node(comp, pns->nodes[1]); // body
1337+
EMIT(label_assign, continue_label);
1338+
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
1339+
#endif
1340+
1341+
// break/continue apply to outer loop (if any) in the else block
1342+
comp->break_label = old_break_label;
1343+
comp->continue_label = old_continue_label;
13311344

13321345
compile_node(comp, pns->nodes[2]); // else
13331346

13341347
EMIT(label_assign, break_label);
1335-
EMIT(label_assign, end_label);
13361348
}
13371349

13381350
void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
@@ -1348,7 +1360,11 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
13481360
comp->continue_label = for_label;
13491361
comp->break_label = break_label;
13501362

1363+
// I don't think our implementation needs SETUP_LOOP/POP_BLOCK for for-statements
1364+
#if MICROPY_EMIT_CPYTHON
13511365
EMIT(setup_loop, end_label);
1366+
#endif
1367+
13521368
compile_node(comp, pns->nodes[1]); // iterator
13531369
EMIT(get_iter);
13541370
EMIT(label_assign, for_label);
@@ -1365,7 +1381,9 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
13651381
comp->break_label = old_break_label;
13661382
comp->continue_label = old_continue_label;
13671383

1384+
#if MICROPY_EMIT_CPYTHON
13681385
EMIT(pop_block);
1386+
#endif
13691387

13701388
compile_node(comp, pns->nodes[3]); // else (not tested)
13711389

py/nlr.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// non-local return
2+
// exception handling, basically a stack of setjmp/longjmp buffers
3+
4+
#include <limits.h>
5+
6+
#ifndef __WORDSIZE
7+
#error __WORDSIZE needs to be defined
8+
#endif
9+
10+
typedef struct _nlr_buf_t nlr_buf_t;
11+
struct _nlr_buf_t {
12+
// the entries here must all be machine word size
13+
nlr_buf_t *prev;
14+
void *ret_val;
15+
#if __WORDSIZE == 32
16+
void *regs[6];
17+
#elif __WORDSIZE == 64
18+
void *regs[8];
19+
#else
20+
#error Unsupported __WORDSIZE
21+
#endif
22+
};
23+
24+
unsigned int nlr_push(nlr_buf_t *);
25+
void nlr_pop();
26+
void nlr_jump(void *val) __attribute__((noreturn));

py/nlrx64.s

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# x64 callee save: bx, bp, sp, r12, r14, r14, r15
2+
3+
.file "nlr.s"
4+
.text
5+
6+
# uint nlr_push(rdi=nlr_buf_t *nlr)
7+
.globl nlr_push
8+
.type nlr_push, @function
9+
nlr_push:
10+
movq (%rsp), %rax # load return %rip
11+
movq %rax, 16(%rdi) # store %rip into nlr_buf
12+
movq %rbp, 24(%rdi) # store %rbp into nlr_buf
13+
movq %rsp, 32(%rdi) # store %rsp into nlr_buf
14+
movq %rbx, 40(%rdi) # store %rbx into nlr_buf
15+
movq %r12, 48(%rdi) # store %r12 into nlr_buf
16+
movq %r13, 56(%rdi) # store %r13 into nlr_buf
17+
movq %r14, 64(%rdi) # store %r14 into nlr_buf
18+
movq %r15, 72(%rdi) # store %r15 into nlr_buf
19+
movq nlr_top(%rip), %rax # get last nlr_buf
20+
movq %rax, (%rdi) # store it
21+
movq %rdi, nlr_top(%rip) # stor new nlr_buf (to make linked list)
22+
xorq %rax, %rax # return 0, normal return
23+
ret # return
24+
.size nlr_push, .-nlr_push
25+
26+
# void nlr_pop()
27+
.globl nlr_pop
28+
.type nlr_pop, @function
29+
nlr_pop:
30+
movq nlr_top(%rip), %rax # get nlr_top into %rax
31+
movq (%rax), %rax # load prev nlr_buf
32+
movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list)
33+
ret # return
34+
.size nlr_pop, .-nlr_pop
35+
36+
# void nlr_jump(rdi=uint val)
37+
.globl nlr_jump
38+
.type nlr_jump, @function
39+
nlr_jump:
40+
movq %rdi, %rax # put return value in %rax
41+
movq nlr_top(%rip), %rdi # get nlr_top into %rdi
42+
movq %rax, 8(%rdi) # store return value
43+
movq (%rdi), %rax # load prev nlr_buf
44+
movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list)
45+
movq 72(%rdi), %r15 # load saved %r15
46+
movq 64(%rdi), %r14 # load saved %r14
47+
movq 56(%rdi), %r13 # load saved %r13
48+
movq 48(%rdi), %r12 # load saved %r12
49+
movq 40(%rdi), %rbx # load saved %rbx
50+
movq 32(%rdi), %rsp # load saved %rsp
51+
movq 24(%rdi), %rbp # load saved %rbp
52+
movq 16(%rdi), %rax # load saved %rip
53+
movq %rax, (%rsp) # store saved %rip to stack
54+
xorq %rax, %rax # clear return register
55+
inc %al # increase to make 1, non-local return
56+
ret # return
57+
.size nlr_jump, .-nlr_jump
58+
59+
.local nlr_top
60+
.comm nlr_top,8,8

py/nlrx86.s

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# x86 callee save: bx, di, si, bp, sp
2+
3+
.file "nlr.s"
4+
.text
5+
6+
# uint nlr_push(4(%esp)=nlr_buf_t *nlr)
7+
.globl nlr_push
8+
.type nlr_push, @function
9+
nlr_push:
10+
mov 4(%esp), %edx # load nlr_buf
11+
mov (%esp), %eax # load return %ip
12+
mov %eax, 8(%edx) # store %ip into nlr_buf+8
13+
mov %ebp, 12(%edx) # store %bp into nlr_buf+12
14+
mov %esp, 16(%edx) # store %sp into nlr_buf+16
15+
mov %ebx, 20(%edx) # store %bx into nlr_buf+20
16+
mov %edi, 24(%edx) # store %di into nlr_buf
17+
mov %esi, 28(%edx) # store %si into nlr_buf
18+
mov nlr_top, %eax # load nlr_top
19+
mov %eax, (%edx) # store it
20+
mov %edx, nlr_top # stor new nlr_buf (to make linked list)
21+
xor %eax, %eax # return 0, normal return
22+
ret # return
23+
.size nlr_push, .-nlr_push
24+
25+
# void nlr_pop()
26+
.globl nlr_pop
27+
.type nlr_pop, @function
28+
nlr_pop:
29+
mov nlr_top, %eax # load nlr_top
30+
mov (%eax), %eax # load prev nlr_buf
31+
mov %eax, nlr_top # store nlr_top (to unlink list)
32+
ret # return
33+
.size nlr_pop, .-nlr_pop
34+
35+
# void nlr_jump(4(%esp)=uint val)
36+
.globl nlr_jump
37+
.type nlr_jump, @function
38+
nlr_jump:
39+
mov nlr_top, %edx # load nlr_top
40+
mov 4(%esp), %eax # load return value
41+
mov %eax, 4(%edx) # store return value
42+
mov (%edx), %eax # load prev nlr_top
43+
mov %eax, nlr_top # store nlr_top (to unlink list)
44+
mov 28(%edx), %esi # load saved %si
45+
mov 24(%edx), %edi # load saved %di
46+
mov 20(%edx), %ebx # load saved %bx
47+
mov 16(%edx), %esp # load saved %sp
48+
mov 12(%edx), %ebp # load saved %bp
49+
mov 8(%edx), %eax # load saved %ip
50+
mov %eax, (%esp) # store saved %ip to stack
51+
xor %eax, %eax # clear return register
52+
inc %al # increase to make 1, non-local return
53+
ret # return
54+
.size nlr_jump, .-nlr_jump
55+
56+
.local nlr_top
57+
.comm nlr_top,4,4

0 commit comments

Comments
 (0)