summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/compile.c40
-rw-r--r--py/nlr.h26
-rw-r--r--py/nlrx64.s60
-rw-r--r--py/nlrx86.s57
-rw-r--r--py/runtime.c114
-rw-r--r--py/runtime.h3
-rw-r--r--py/vm.c500
7 files changed, 566 insertions, 234 deletions
diff --git a/py/compile.c b/py/compile.c
index c1d49102be..0967c855c4 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -16,6 +16,8 @@
// TODO need to mangle __attr names
+#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
+
typedef enum {
PN_none = 0,
#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_
}
qstr attr = PY_PARSE_NODE_LEAF_ARG(name_nodes[1]);
- if (attr == comp->qstr_native) {
+ if (0) {
+#if MICROPY_EMIT_NATIVE
+ } else if (attr == comp->qstr_native) {
*emit_options = EMIT_OPT_NATIVE_PYTHON;
} else if (attr == comp->qstr_viper) {
*emit_options = EMIT_OPT_VIPER;
+#endif
#if MICROPY_EMIT_INLINE_THUMB
} else if (attr == comp->qstr_asm_thumb) {
*emit_options = EMIT_OPT_ASM_THUMB;
#endif
} else {
- printf("SyntaxError: invalid micropython decorator\n");
+ printf("SyntaxError: invalid micropython decorator '%s'\n", qstr_str(attr));
}
return true;
@@ -1302,15 +1307,16 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
int old_break_label = comp->break_label;
int old_continue_label = comp->continue_label;
- int done_label = comp_next_label(comp);
- int end_label = comp_next_label(comp);
int break_label = comp_next_label(comp);
int continue_label = comp_next_label(comp);
comp->break_label = break_label;
comp->continue_label = continue_label;
- EMIT(setup_loop, end_label);
+ // compared to CPython, we have an optimised version of while loops
+#if MICROPY_EMIT_CPYTHON
+ int done_label = comp_next_label(comp);
+ EMIT(setup_loop, break_label);
EMIT(label_assign, continue_label);
c_if_cond(comp, pns->nodes[0], false, done_label); // condition
compile_node(comp, pns->nodes[1]); // body
@@ -1318,21 +1324,27 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
EMIT(jump, continue_label);
}
EMIT(label_assign, done_label);
-
- // break/continue apply to outer loop (if any) in the else block
- comp->break_label = old_break_label;
- comp->continue_label = old_continue_label;
-
// CPython does not emit POP_BLOCK if the condition was a constant; don't undertand why
// this is a small hack to agree with CPython
if (!node_is_const_true(pns->nodes[0])) {
EMIT(pop_block);
}
+#else
+ int top_label = comp_next_label(comp);
+ EMIT(jump, continue_label);
+ EMIT(label_assign, top_label);
+ compile_node(comp, pns->nodes[1]); // body
+ EMIT(label_assign, continue_label);
+ c_if_cond(comp, pns->nodes[0], true, top_label); // condition
+#endif
+
+ // break/continue apply to outer loop (if any) in the else block
+ comp->break_label = old_break_label;
+ comp->continue_label = old_continue_label;
compile_node(comp, pns->nodes[2]); // else
EMIT(label_assign, break_label);
- EMIT(label_assign, end_label);
}
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) {
comp->continue_label = for_label;
comp->break_label = break_label;
+ // I don't think our implementation needs SETUP_LOOP/POP_BLOCK for for-statements
+#if MICROPY_EMIT_CPYTHON
EMIT(setup_loop, end_label);
+#endif
+
compile_node(comp, pns->nodes[1]); // iterator
EMIT(get_iter);
EMIT(label_assign, for_label);
@@ -1365,7 +1381,9 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
comp->break_label = old_break_label;
comp->continue_label = old_continue_label;
+#if MICROPY_EMIT_CPYTHON
EMIT(pop_block);
+#endif
compile_node(comp, pns->nodes[3]); // else (not tested)
diff --git a/py/nlr.h b/py/nlr.h
new file mode 100644
index 0000000000..b824e4a63a
--- /dev/null
+++ b/py/nlr.h
@@ -0,0 +1,26 @@
+// non-local return
+// exception handling, basically a stack of setjmp/longjmp buffers
+
+#include <limits.h>
+
+#ifndef __WORDSIZE
+#error __WORDSIZE needs to be defined
+#endif
+
+typedef struct _nlr_buf_t nlr_buf_t;
+struct _nlr_buf_t {
+ // the entries here must all be machine word size
+ nlr_buf_t *prev;
+ void *ret_val;
+#if __WORDSIZE == 32
+ void *regs[6];
+#elif __WORDSIZE == 64
+ void *regs[8];
+#else
+#error Unsupported __WORDSIZE
+#endif
+};
+
+unsigned int nlr_push(nlr_buf_t *);
+void nlr_pop();
+void nlr_jump(void *val) __attribute__((noreturn));
diff --git a/py/nlrx64.s b/py/nlrx64.s
new file mode 100644
index 0000000000..cf0eb3cd71
--- /dev/null
+++ b/py/nlrx64.s
@@ -0,0 +1,60 @@
+# x64 callee save: bx, bp, sp, r12, r14, r14, r15
+
+ .file "nlr.s"
+ .text
+
+# uint nlr_push(rdi=nlr_buf_t *nlr)
+ .globl nlr_push
+ .type nlr_push, @function
+nlr_push:
+ movq (%rsp), %rax # load return %rip
+ movq %rax, 16(%rdi) # store %rip into nlr_buf
+ movq %rbp, 24(%rdi) # store %rbp into nlr_buf
+ movq %rsp, 32(%rdi) # store %rsp into nlr_buf
+ movq %rbx, 40(%rdi) # store %rbx into nlr_buf
+ movq %r12, 48(%rdi) # store %r12 into nlr_buf
+ movq %r13, 56(%rdi) # store %r13 into nlr_buf
+ movq %r14, 64(%rdi) # store %r14 into nlr_buf
+ movq %r15, 72(%rdi) # store %r15 into nlr_buf
+ movq nlr_top(%rip), %rax # get last nlr_buf
+ movq %rax, (%rdi) # store it
+ movq %rdi, nlr_top(%rip) # stor new nlr_buf (to make linked list)
+ xorq %rax, %rax # return 0, normal return
+ ret # return
+ .size nlr_push, .-nlr_push
+
+# void nlr_pop()
+ .globl nlr_pop
+ .type nlr_pop, @function
+nlr_pop:
+ movq nlr_top(%rip), %rax # get nlr_top into %rax
+ movq (%rax), %rax # load prev nlr_buf
+ movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list)
+ ret # return
+ .size nlr_pop, .-nlr_pop
+
+# void nlr_jump(rdi=uint val)
+ .globl nlr_jump
+ .type nlr_jump, @function
+nlr_jump:
+ movq %rdi, %rax # put return value in %rax
+ movq nlr_top(%rip), %rdi # get nlr_top into %rdi
+ movq %rax, 8(%rdi) # store return value
+ movq (%rdi), %rax # load prev nlr_buf
+ movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list)
+ movq 72(%rdi), %r15 # load saved %r15
+ movq 64(%rdi), %r14 # load saved %r14
+ movq 56(%rdi), %r13 # load saved %r13
+ movq 48(%rdi), %r12 # load saved %r12
+ movq 40(%rdi), %rbx # load saved %rbx
+ movq 32(%rdi), %rsp # load saved %rsp
+ movq 24(%rdi), %rbp # load saved %rbp
+ movq 16(%rdi), %rax # load saved %rip
+ movq %rax, (%rsp) # store saved %rip to stack
+ xorq %rax, %rax # clear return register
+ inc %al # increase to make 1, non-local return
+ ret # return
+ .size nlr_jump, .-nlr_jump
+
+ .local nlr_top
+ .comm nlr_top,8,8
diff --git a/py/nlrx86.s b/py/nlrx86.s
new file mode 100644
index 0000000000..364766da70
--- /dev/null
+++ b/py/nlrx86.s
@@ -0,0 +1,57 @@
+# x86 callee save: bx, di, si, bp, sp
+
+ .file "nlr.s"
+ .text
+
+# uint nlr_push(4(%esp)=nlr_buf_t *nlr)
+ .globl nlr_push
+ .type nlr_push, @function
+nlr_push:
+ mov 4(%esp), %edx # load nlr_buf
+ mov (%esp), %eax # load return %ip
+ mov %eax, 8(%edx) # store %ip into nlr_buf+8
+ mov %ebp, 12(%edx) # store %bp into nlr_buf+12
+ mov %esp, 16(%edx) # store %sp into nlr_buf+16
+ mov %ebx, 20(%edx) # store %bx into nlr_buf+20
+ mov %edi, 24(%edx) # store %di into nlr_buf
+ mov %esi, 28(%edx) # store %si into nlr_buf
+ mov nlr_top, %eax # load nlr_top
+ mov %eax, (%edx) # store it
+ mov %edx, nlr_top # stor new nlr_buf (to make linked list)
+ xor %eax, %eax # return 0, normal return
+ ret # return
+ .size nlr_push, .-nlr_push
+
+# void nlr_pop()
+ .globl nlr_pop
+ .type nlr_pop, @function
+nlr_pop:
+ mov nlr_top, %eax # load nlr_top
+ mov (%eax), %eax # load prev nlr_buf
+ mov %eax, nlr_top # store nlr_top (to unlink list)
+ ret # return
+ .size nlr_pop, .-nlr_pop
+
+# void nlr_jump(4(%esp)=uint val)
+ .globl nlr_jump
+ .type nlr_jump, @function
+nlr_jump:
+ mov nlr_top, %edx # load nlr_top
+ mov 4(%esp), %eax # load return value
+ mov %eax, 4(%edx) # store return value
+ mov (%edx), %eax # load prev nlr_top
+ mov %eax, nlr_top # store nlr_top (to unlink list)
+ mov 28(%edx), %esi # load saved %si
+ mov 24(%edx), %edi # load saved %di
+ mov 20(%edx), %ebx # load saved %bx
+ mov 16(%edx), %esp # load saved %sp
+ mov 12(%edx), %ebp # load saved %bp
+ mov 8(%edx), %eax # load saved %ip
+ mov %eax, (%esp) # store saved %ip to stack
+ xor %eax, %eax # clear return register
+ inc %al # increase to make 1, non-local return
+ ret # return
+ .size nlr_jump, .-nlr_jump
+
+ .local nlr_top
+ .comm nlr_top,4,4
diff --git a/py/runtime.c b/py/runtime.c
index f06c9203a2..e13adfaa42 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <assert.h>
+#include "nlr.h"
#include "misc.h"
#include "mpyconfig.h"
#include "runtime.h"
@@ -36,6 +37,10 @@ typedef enum {
#if MICROPY_ENABLE_FLOAT
O_FLOAT,
#endif
+ O_EXCEPTION_0,
+ O_EXCEPTION_2,
+ O_RANGE,
+ O_RANGE_IT,
O_FUN_0,
O_FUN_1,
O_FUN_2,
@@ -77,6 +82,28 @@ struct _py_obj_base_t {
#if MICROPY_ENABLE_FLOAT
float_t u_flt;
#endif
+ struct { // for O_EXCEPTION_0
+ qstr id;
+ } u_exc0;
+ struct { // for O_EXCEPTION_2
+ // TODO reduce size or make generic object or something
+ qstr id;
+ const char *fmt;
+ const char *s1;
+ const char *s2;
+ } u_exc2;
+ struct { // for O_RANGE
+ // TODO make generic object or something
+ machine_int_t start;
+ machine_int_t stop;
+ machine_int_t step;
+ } u_range;
+ struct { // for O_RANGE_IT
+ // TODO make generic object or something
+ machine_int_t cur;
+ machine_int_t stop;
+ machine_int_t step;
+ } u_range_it;
struct { // for O_FUN_[012N]
int n_args;
void *fun;
@@ -118,6 +145,7 @@ struct _py_obj_base_t {
py_obj_t py_const_none;
py_obj_t py_const_false;
py_obj_t py_const_true;
+py_obj_t py_const_stop_iteration;
// locals and globals need to be pointers because they can be the same in outer module scope
py_map_t *map_locals;
@@ -266,6 +294,42 @@ py_obj_t py_obj_new_float(float_t val) {
}
#endif
+py_obj_t py_obj_new_exception_0(qstr id) {
+ py_obj_base_t *o = m_new(py_obj_base_t, 1);
+ o->kind = O_EXCEPTION_0;
+ o->u_exc0.id = id;
+ return (py_obj_t)o;
+}
+
+py_obj_t py_obj_new_exception_2(qstr id, const char *fmt, const char *s1, const char *s2) {
+ py_obj_base_t *o = m_new(py_obj_base_t, 1);
+ o->kind = O_EXCEPTION_2;
+ o->u_exc2.id = id;
+ o->u_exc2.fmt = fmt;
+ o->u_exc2.s1 = s1;
+ o->u_exc2.s2 = s2;
+ return (py_obj_t)o;
+}
+
+// range is a class and instances are immutable sequence objects
+py_obj_t py_obj_new_range(int start, int stop, int step) {
+ py_obj_base_t *o = m_new(py_obj_base_t, 1);
+ o->kind = O_RANGE;
+ o->u_range.start = start;
+ o->u_range.stop = stop;
+ o->u_range.step = step;
+ return o;
+}
+
+py_obj_t py_obj_new_range_iterator(int cur, int stop, int step) {
+ py_obj_base_t *o = m_new(py_obj_base_t, 1);
+ o->kind = O_RANGE_IT;
+ o->u_range_it.cur = cur;
+ o->u_range_it.stop = stop;
+ o->u_range_it.step = step;
+ return o;
+}
+
py_obj_t list_append(py_obj_t self_in, py_obj_t arg) {
assert(IS_O(self_in, O_LIST));
py_obj_base_t *self = self_in;
@@ -281,6 +345,9 @@ static qstr q_append;
static qstr q_print;
static qstr q_len;
static qstr q___build_class__;
+static qstr q_AttributeError;
+static qstr q_NameError;
+static qstr q_TypeError;
typedef enum {
PY_CODE_NONE,
@@ -356,6 +423,10 @@ py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name)
return o;
}
+py_obj_t py_builtin_range(py_obj_t o_arg) {
+ return py_obj_new_range(0, rt_get_int(o_arg), 1);
+}
+
#ifdef WRITE_NATIVE
FILE *fp_native = NULL;
#endif
@@ -365,10 +436,14 @@ void rt_init() {
q_print = qstr_from_str_static("print");
q_len = qstr_from_str_static("len");
q___build_class__ = qstr_from_str_static("__build_class__");
+ q_AttributeError = qstr_from_str_static("AttributeError");
+ q_NameError = qstr_from_str_static("NameError");
+ q_TypeError = qstr_from_str_static("TypeError");
py_const_none = py_obj_new_const("None");
py_const_false = py_obj_new_const("False");
py_const_true = py_obj_new_const("True");
+ py_const_stop_iteration = py_obj_new_const("StopIteration");
// locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
map_locals = map_globals = py_map_new(MAP_QSTR, 1);
@@ -378,6 +453,7 @@ void rt_init() {
py_qstr_map_lookup(&map_builtins, q_print, true)->value = rt_make_function_1(py_builtin_print);
py_qstr_map_lookup(&map_builtins, q_len, true)->value = rt_make_function_1(py_builtin_len);
py_qstr_map_lookup(&map_builtins, q___build_class__, true)->value = rt_make_function_2(py_builtin___build_class__);
+ py_qstr_map_lookup(&map_builtins, qstr_from_str_static("range"), true)->value = rt_make_function_1(py_builtin_range);
next_unique_code_id = 1;
unique_codes = NULL;
@@ -559,6 +635,10 @@ void py_obj_print(py_obj_t o_in) {
printf("%f", o->u_flt);
break;
#endif
+ case O_EXCEPTION_2:
+ printf("%s: ", qstr_str(o->u_exc2.id));
+ printf(o->u_exc2.fmt, o->u_exc2.s1, o->u_exc2.s2);
+ break;
case O_LIST:
printf("[");
for (int i = 0; i < o->u_list.len; i++) {
@@ -653,8 +733,7 @@ py_obj_t rt_load_name(qstr qstr) {
if (elem == NULL) {
elem = py_qstr_map_lookup(&map_builtins, qstr, false);
if (elem == NULL) {
- printf("name doesn't exist: %s\n", qstr_str(qstr));
- assert(0);
+ nlr_jump(py_obj_new_exception_2(q_NameError, "name '%s' is not defined", qstr_str(qstr), NULL));
}
}
}
@@ -668,8 +747,7 @@ py_obj_t rt_load_global(qstr qstr) {
if (elem == NULL) {
elem = py_qstr_map_lookup(&map_builtins, qstr, false);
if (elem == NULL) {
- printf("name doesn't exist: %s\n", qstr_str(qstr));
- assert(0);
+ nlr_jump(py_obj_new_exception_2(q_NameError, "name '%s' is not defined", qstr_str(qstr), NULL));
}
}
return elem->value;
@@ -1123,9 +1201,7 @@ py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
}
no_attr:
- printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
- assert(0);
- return py_const_none;
+ nlr_jump(py_obj_new_exception_2(q_AttributeError, "'%s' object has no attribute '%s'", py_obj_get_type_str(base), qstr_str(attr)));
}
void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
@@ -1204,6 +1280,30 @@ void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
}
}
+py_obj_t rt_getiter(py_obj_t o_in) {
+ if (IS_O(o_in, O_RANGE)) {
+ py_obj_base_t *o = o_in;
+ return py_obj_new_range_iterator(o->u_range.start, o->u_range.stop, o->u_range.step);
+ } else {
+ nlr_jump(py_obj_new_exception_2(q_TypeError, "'%s' object is not iterable", py_obj_get_type_str(o_in), NULL));
+ }
+}
+
+py_obj_t rt_iternext(py_obj_t o_in) {
+ if (IS_O(o_in, O_RANGE_IT)) {
+ py_obj_base_t *o = o_in;
+ if ((o->u_range_it.step > 0 && o->u_range_it.cur < o->u_range_it.stop) || (o->u_range_it.step < 0 && o->u_range_it.cur > o->u_range_it.stop)) {
+ py_obj_t o_out = TO_SMALL_INT(o->u_range_it.cur);
+ o->u_range_it.cur += o->u_range_it.step;
+ return o_out;
+ } else {
+ return py_const_stop_iteration;
+ }
+ } else {
+ nlr_jump(py_obj_new_exception_2(q_TypeError, "? '%s' object is not iterable", py_obj_get_type_str(o_in), NULL));
+ }
+}
+
void *rt_fun_table[RT_F_NUMBER_OF] = {
rt_load_const_str,
rt_load_name,
diff --git a/py/runtime.h b/py/runtime.h
index 2823ba187d..c36f8d8e7e 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -82,6 +82,7 @@ typedef py_obj_t (*py_fun_t)();
extern py_obj_t py_const_none;
extern py_obj_t py_const_false;
extern py_obj_t py_const_true;
+extern py_obj_t py_const_stop_iteration; // special object indicating end of iteration (not StopIteration exception!)
void rt_init();
void rt_deinit();
@@ -123,3 +124,5 @@ py_obj_t rt_load_attr(py_obj_t base, qstr attr);
void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest);
void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val);
void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t val);
+py_obj_t rt_getiter(py_obj_t o);
+py_obj_t rt_iternext(py_obj_t o);
diff --git a/py/vm.c b/py/vm.c
index d6740cf04d..e92229a073 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <assert.h>
+#include "nlr.h"
#include "misc.h"
#include "mpyconfig.h"
#include "runtime.h"
@@ -24,6 +25,7 @@ py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args,
qstr qstr;
py_obj_t obj1, obj2;
py_obj_t fast0 = NULL, fast1 = NULL, fast2 = NULL, fastn[4] = {NULL, NULL, NULL, NULL};
+ nlr_buf_t nlr;
// init args
for (int i = 0; i < n_args; i++) {
@@ -39,224 +41,290 @@ py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args,
}
}
- // execute byte code
+ // outer exception handling loop
for (;;) {
- int op = *ip++;
- switch (op) {
- case PYBC_LOAD_CONST_FALSE:
- PUSH(py_const_false);
- break;
-
- case PYBC_LOAD_CONST_NONE:
- PUSH(py_const_none);
- break;
-
- case PYBC_LOAD_CONST_TRUE:
- PUSH(py_const_true);
- break;
-
- case PYBC_LOAD_CONST_SMALL_INT:
- snum = ip[0] | (ip[1] << 8);
- if (snum & 0x8000) {
- snum |= ~0xffff;
+ if (nlr_push(&nlr) == 0) {
+ // loop to execute byte code
+ for (;;) {
+ int op = *ip++;
+ switch (op) {
+ case PYBC_LOAD_CONST_FALSE:
+ PUSH(py_const_false);
+ break;
+
+ case PYBC_LOAD_CONST_NONE:
+ PUSH(py_const_none);
+ break;
+
+ case PYBC_LOAD_CONST_TRUE:
+ PUSH(py_const_true);
+ break;
+
+ case PYBC_LOAD_CONST_SMALL_INT:
+ snum = ip[0] | (ip[1] << 8);
+ if (snum & 0x8000) {
+ snum |= ~0xffff;
+ }
+ ip += 2;
+ PUSH((py_obj_t)(snum << 1 | 1));
+ break;
+
+ case PYBC_LOAD_CONST_ID:
+ DECODE_QSTR;
+ PUSH(rt_load_const_str(qstr)); // TODO
+ break;
+
+ case PYBC_LOAD_CONST_STRING:
+ DECODE_QSTR;
+ PUSH(rt_load_const_str(qstr));
+ break;
+
+ case PYBC_LOAD_FAST_0:
+ PUSH(fast0);
+ break;
+
+ case PYBC_LOAD_FAST_1:
+ PUSH(fast1);
+ break;
+
+ case PYBC_LOAD_FAST_2:
+ PUSH(fast2);
+ break;
+
+ case PYBC_LOAD_FAST_N:
+ DECODE_UINT;
+ PUSH(fastn[unum - 3]);
+ break;
+
+ case PYBC_LOAD_NAME:
+ DECODE_QSTR;
+ PUSH(rt_load_name(qstr));
+ break;
+
+ case PYBC_LOAD_GLOBAL:
+ DECODE_QSTR;
+ PUSH(rt_load_global(qstr));
+ break;
+
+ case PYBC_LOAD_ATTR:
+ DECODE_QSTR;
+ *sp = rt_load_attr(*sp, qstr);
+ break;
+
+ case PYBC_LOAD_METHOD:
+ DECODE_QSTR;
+ sp -= 1;
+ rt_load_method(sp[1], qstr, sp);
+ break;
+
+ case PYBC_LOAD_BUILD_CLASS:
+ PUSH(rt_load_build_class());
+ break;
+
+ case PYBC_STORE_FAST_0:
+ fast0 = POP();
+ break;
+
+ case PYBC_STORE_FAST_1:
+ fast1 = POP();
+ break;
+
+ case PYBC_STORE_FAST_2:
+ fast2 = POP();
+ break;
+
+ case PYBC_STORE_FAST_N:
+ DECODE_UINT;
+ fastn[unum - 3] = POP();
+ break;
+
+ case PYBC_STORE_NAME:
+ DECODE_QSTR;
+ rt_store_name(qstr, POP());
+ break;
+
+ case PYBC_STORE_ATTR:
+ DECODE_QSTR;
+ rt_store_attr(sp[0], qstr, sp[1]);
+ sp += 2;
+ break;
+
+ case PYBC_STORE_SUBSCR:
+ rt_store_subscr(sp[1], sp[0], sp[2]);
+ sp += 3;
+ break;
+
+ case PYBC_DUP_TOP:
+ obj1 = *sp;
+ PUSH(obj1);
+ break;
+
+ case PYBC_DUP_TOP_TWO:
+ sp -= 2;
+ sp[0] = sp[2];
+ sp[1] = sp[3];
+ break;
+
+ case PYBC_POP_TOP:
+ ++sp;
+ break;
+
+ case PYBC_ROT_THREE:
+ obj1 = sp[0];
+ sp[0] = sp[1];
+ sp[1] = sp[2];
+ sp[2] = obj1;
+ break;
+
+ case PYBC_JUMP:
+ DECODE_UINT;
+ ip = code + unum;
+ break;
+
+ case PYBC_POP_JUMP_IF_TRUE:
+ DECODE_UINT;
+ if (rt_is_true(POP())) {
+ ip = code + unum;
+ }
+ break;
+
+ case PYBC_POP_JUMP_IF_FALSE:
+ DECODE_UINT;
+ if (!rt_is_true(POP())) {
+ ip = code + unum;
+ }
+ break;
+
+ /* we are trying to get away without using this opcode
+ case PYBC_SETUP_LOOP:
+ DECODE_UINT;
+ // push_block(PYBC_SETUP_LOOP, code + unum, sp)
+ break;
+ */
+
+ case PYBC_SETUP_EXCEPT:
+ // push_block(PYBC_SETUP_EXCEPT, code + unum, sp)
+ assert(0);
+ break;
+
+ case PYBC_END_FINALLY:
+ // not implemented
+ // if TOS is an exception, reraises the exception (3 values on TOS)
+ // if TOS is an integer, does something else
+ // if TOS is None, just pops it and continues
+ // else error
+ assert(0);
+ break;
+
+ case PYBC_GET_ITER:
+ *sp = rt_getiter(*sp);
+ break;
+
+ case PYBC_FOR_ITER:
+ DECODE_UINT; // the jump offset if iteration finishes
+ obj1 = rt_iternext(*sp);
+ if (obj1 == py_const_stop_iteration) {
+ ++sp; // pop the exhausted iterator
+ ip = code + unum; // jump to after for-block
+ } else {
+ PUSH(obj1); // push the next iteration value
+ }
+ break;
+
+ case PYBC_POP_BLOCK:
+ // pops block and restores the stack
+ assert(0);
+ break;
+
+ case PYBC_POP_EXCEPT:
+ // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
+ assert(0);
+ break;
+
+ case PYBC_BINARY_OP:
+ unum = *ip++;
+ obj2 = POP();
+ obj1 = *sp;
+ *sp = rt_binary_op(unum, obj1, obj2);
+ break;
+
+ case PYBC_COMPARE_OP:
+ unum = *ip++;
+ obj2 = POP();
+ obj1 = *sp;
+ *sp = rt_compare_op(unum, obj1, obj2);
+ break;
+
+ case PYBC_BUILD_LIST:
+ DECODE_UINT;
+ obj1 = rt_build_list(unum, sp);
+ sp += unum - 1;
+ *sp = obj1;
+ break;
+
+ case PYBC_BUILD_MAP:
+ DECODE_UINT;
+ PUSH(rt_build_map(unum));
+ break;
+
+ case PYBC_STORE_MAP:
+ sp += 2;
+ rt_store_map(sp[0], sp[-2], sp[-1]);
+ break;
+
+ case PYBC_BUILD_SET:
+ DECODE_UINT;
+ obj1 = rt_build_set(unum, sp);
+ sp += unum - 1;
+ *sp = obj1;
+ break;
+
+ case PYBC_MAKE_FUNCTION:
+ DECODE_UINT;
+ PUSH(rt_make_function_from_id(unum));
+ break;
+
+ case PYBC_CALL_FUNCTION:
+ DECODE_UINT;
+ assert((unum & 0xff00) == 0); // n_keyword
+ unum &= 0xff; // n_positional
+ sp += unum;
+ *sp = rt_call_function_n(*sp, unum, sp - unum);
+ break;
+
+ case PYBC_CALL_METHOD:
+ DECODE_UINT;
+ assert((unum & 0xff00) == 0); // n_keyword
+ unum &= 0xff;
+ obj1 = rt_call_method_n(unum, sp);
+ sp += unum + 1;
+ *sp = obj1;
+ break;
+
+ case PYBC_RETURN_VALUE:
+ nlr_pop();
+ return *sp;
+
+ default:
+ printf("code %p, offset %u, byte code 0x%02x not implemented\n", code, (uint)(ip - code), op);
+ assert(0);
+ nlr_pop();
+ return py_const_none;
}
- ip += 2;
- PUSH((py_obj_t)(snum << 1 | 1));
- break;
-
- case PYBC_LOAD_CONST_ID:
- DECODE_QSTR;
- PUSH(rt_load_const_str(qstr)); // TODO
- break;
-
- case PYBC_LOAD_CONST_STRING:
- DECODE_QSTR;
- PUSH(rt_load_const_str(qstr));
- break;
-
- case PYBC_LOAD_FAST_0:
- PUSH(fast0);
- break;
-
- case PYBC_LOAD_FAST_1:
- PUSH(fast1);
- break;
-
- case PYBC_LOAD_FAST_2:
- PUSH(fast2);
- break;
-
- case PYBC_LOAD_FAST_N:
- DECODE_UINT;
- PUSH(fastn[unum - 3]);
- break;
-
- case PYBC_LOAD_NAME:
- DECODE_QSTR;
- PUSH(rt_load_name(qstr));
- break;
-
- case PYBC_LOAD_GLOBAL:
- DECODE_QSTR;
- PUSH(rt_load_global(qstr));
- break;
-
- case PYBC_LOAD_ATTR:
- DECODE_QSTR;
- *sp = rt_load_attr(*sp, qstr);
- break;
-
- case PYBC_LOAD_METHOD:
- DECODE_QSTR;
- sp -= 1;
- rt_load_method(sp[1], qstr, sp);
- break;
-
- case PYBC_LOAD_BUILD_CLASS:
- PUSH(rt_load_build_class());
- break;
-
- case PYBC_STORE_FAST_0:
- fast0 = POP();
- break;
-
- case PYBC_STORE_FAST_1:
- fast1 = POP();
- break;
-
- case PYBC_STORE_FAST_2:
- fast2 = POP();
- break;
-
- case PYBC_STORE_FAST_N:
- DECODE_UINT;
- fastn[unum - 3] = POP();
- break;
-
- case PYBC_STORE_NAME:
- DECODE_QSTR;
- rt_store_name(qstr, POP());
- break;
-
- case PYBC_STORE_ATTR:
- DECODE_QSTR;
- rt_store_attr(sp[0], qstr, sp[1]);
- sp += 2;
- break;
-
- case PYBC_STORE_SUBSCR:
- rt_store_subscr(sp[1], sp[0], sp[2]);
- sp += 3;
- break;
-
- case PYBC_DUP_TOP:
- obj1 = *sp;
- PUSH(obj1);
- break;
-
- case PYBC_DUP_TOP_TWO:
- sp -= 2;
- sp[0] = sp[2];
- sp[1] = sp[3];
- break;
-
- case PYBC_POP_TOP:
- ++sp;
- break;
-
- case PYBC_ROT_THREE:
- obj1 = sp[0];
- sp[0] = sp[1];
- sp[1] = sp[2];
- sp[2] = obj1;
- break;
-
- case PYBC_JUMP:
- DECODE_UINT;
- ip = code + unum;
- break;
-
- case PYBC_POP_JUMP_IF_FALSE:
- DECODE_UINT;
- if (!rt_is_true(POP())) {
- ip = code + unum;
- }
- break;
-
- case PYBC_SETUP_LOOP:
- DECODE_UINT;
- break;
-
- case PYBC_POP_BLOCK:
- break;
-
- case PYBC_BINARY_OP:
- unum = *ip++;
- obj2 = POP();
- obj1 = *sp;
- *sp = rt_binary_op(unum, obj1, obj2);
- break;
-
- case PYBC_COMPARE_OP:
- unum = *ip++;
- obj2 = POP();
- obj1 = *sp;
- *sp = rt_compare_op(unum, obj1, obj2);
- break;
-
- case PYBC_BUILD_LIST:
- DECODE_UINT;
- obj1 = rt_build_list(unum, sp);
- sp += unum - 1;
- *sp = obj1;
- break;
-
- case PYBC_BUILD_MAP:
- DECODE_UINT;
- PUSH(rt_build_map(unum));
- break;
-
- case PYBC_STORE_MAP:
- sp += 2;
- rt_store_map(sp[0], sp[-2], sp[-1]);
- break;
-
- case PYBC_BUILD_SET:
- DECODE_UINT;
- obj1 = rt_build_set(unum, sp);
- sp += unum - 1;
- *sp = obj1;
- break;
-
- case PYBC_MAKE_FUNCTION:
- DECODE_UINT;
- PUSH(rt_make_function_from_id(unum));
- break;
-
- case PYBC_CALL_FUNCTION:
- DECODE_UINT;
- assert((unum & 0xff00) == 0); // n_keyword
- unum &= 0xff; // n_positional
- sp += unum;
- *sp = rt_call_function_n(*sp, unum, sp - unum);
- break;
-
- case PYBC_CALL_METHOD:
- DECODE_UINT;
- assert((unum & 0xff00) == 0); // n_keyword
- unum &= 0xff;
- obj1 = rt_call_method_n(unum, sp);
- sp += unum + 1;
- *sp = obj1;
- break;
-
- case PYBC_RETURN_VALUE:
- return *sp;
-
- default:
- printf("code %p, offset %u, byte code 0x%02x not implemented\n", code, (uint)(ip - code), op);
- assert(0);
- return py_const_none;
+ }
+
+ } else {
+ // exception occurred
+
+ if (0) {
+ // catch exception and pass to byte code
+ //ip = pop
+ //sp = pop
+ //push(traceback, exc-val, exc-type)
+ } else {
+ // re-raise exception
+ nlr_jump(nlr.ret_val);
+ }
}
}
}